Scenario 2: Locations and Spacings
Use graphical methods to examine the spacings between consecutive palindromes and sum of consecutive pairs, triplets, etc, spacings. Compare what you find to what you would expect to find in a random scatter. Also, use graphical methods to compare locations of the palindromes.
# Chi-square Goodness of Fit Test
# Case 1: k(number of sub-intervals)=20
k <- 20
locations.expected <- n/k
tab <- table(cut(locations, breaks=seq(0, N, length.out=k+1), include.lowest=TRUE))
locations.observed <- as.vector(tab)
chi_2 <- sum((locations.observed - locations.expected)^2/locations.expected)
chi2_compare <- qchisq(p=0.95, df=19)
p_value <- pchisq(chi_2, df=19, lower.tail=FALSE)
print(cat('\nWhen conducting chi_square Goodness of fit test comparing locations(divided in 20 sub-intervals) against uniform distribution\n'))
When conducting chi_square Goodness of fit test comparing locations(divided in 20 sub-intervals) against uniform distribution
NULL
print(paste('The value of chi_square statistic is', chi_2))
[1] "The value of chi_square statistic is 17.9189189189189"
print(paste('The p_value is', p_value))
[1] "The p_value is 0.527860332119311"
## Visualization of the Residual
Residuals <- (locations.observed - locations.expected) / sqrt(locations.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 20 sub-intervals)')

# Case 2: k(number of sub-intervals)=30
k <- 30
locations.expected <- n/k
tab <- table(cut(locations, breaks=seq(0, N, length.out=k+1), include.lowest=TRUE))
locations.observed <- as.vector(tab)
chi_2 <- sum((locations.observed - locations.expected)^2/locations.expected)
chi2_compare <- qchisq(p=0.95, df=29)
p_value <- pchisq(chi_2, df=29, lower.tail=FALSE)
print(cat('\nWhen conducting chi_square Goodness of fit test comparing locations(divided in 30 sub-intervals) against uniform distribution\n'))
When conducting chi_square Goodness of fit test comparing locations(divided in 30 sub-intervals) against uniform distribution
NULL
print(paste('The value of chi_square statistic is', chi_2))
[1] "The value of chi_square statistic is 40.6891891891892"
print(paste('The p_value is', p_value))
[1] "The p_value is 0.0732835870345071"
## Visualization of the Residual
Residuals <- (locations.observed - locations.expected) / sqrt(locations.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 30 sub-intervals)')

# Case 3: k(number of sub-intervals)=60
k <- 60
locations.expected <- n/k
tab <- table(cut(locations, breaks=seq(0, N, length.out=k+1), include.lowest=TRUE))
locations.observed <- as.vector(tab)
chi_2 <- sum((locations.observed - locations.expected)^2/locations.expected)
chi2_compare <- qchisq(p=0.95, df=59)
p_value <- pchisq(chi_2, df=59, lower.tail=FALSE)
print(cat('\nWhen conducting chi_square Goodness of fit test comparing locations(divided in 60 sub-intervals) against uniform distribution\n'))
When conducting chi_square Goodness of fit test comparing locations(divided in 60 sub-intervals) against uniform distribution
NULL
print(paste('The value of chi_square statistic is', chi_2))
[1] "The value of chi_square statistic is 79"
print(paste('The p_value is', p_value))
[1] "The p_value is 0.0421403871302519"
## Visualization of the Residual
Residuals <- (locations.observed - locations.expected) / sqrt(locations.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 60 sub-intervals)')

# Histogram of locations of palindromes in original data and uniform scatter
sample <- runif(n, min=0, max=N)
title <- 'Locations of Palindromes (Original vs. Simulated)'
x.axis <- 'Base Pair'
bins <- 35
hist(locations, breaks=bins, probability=TRUE, col=rgb(1,0,0,0.5), main=title, xlab=x.axis)
lines(density(locations, adjust=2), col=2)
hist(sample, breaks=bins, probability=TRUE, col=rgb(0,0,1,0.5), add=TRUE)
lines(density(sample, adjust=2), col=4)
legend('topright', legend=c('Original', 'Uniform'), lty=c(1,1), col=c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Single Palindrome Spacing
locations.sorted = sort(locations, decreasing = FALSE)
distance.single <- abs(locations.sorted[-1]-locations.sorted[-length(locations.sorted)])
# Histogram of spacings of palindromes in original data and exponential distribution
hist(distance.single, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Consecutive palindrome Spacings Distribution Comparison", xlab = "Distance between Consecutive Palindromes", ylim = c(0,0.001))
lines(density(distance.single, adjust = 2), col = rgb(1,0,0,0.5))
Expo <- rexp(n-1, rate = 1/mean(distance.single))
hist(Expo, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Expo, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 4200, y = 0.0009, legend = c("Sample", "Exponential"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Chi-square Goodness of Fit Test
# Case 1: Divided in 7 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.single, decreasing = FALSE)
lambda <- 1/mean(distance.single)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(0,0.05, 0.1, 0.3, 0.5, 0.7, 0.9,1)))
spacings.expected <- (n-1)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.single, breaks=spacings.intervals, include.lowest=TRUE)))
contingency_7 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_7
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=5)
p_value <- pchisq(chi_2, df=5, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 7 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 7 sub-intervals is 6.42447875347949e-05"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 7 bins)')

# Case 2: Divided in 10 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.single, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.1))))
spacings.expected <- (n-1)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.single, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_10 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_10
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=8)
p_value <- pchisq(chi_2, df=8, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 10 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 10 sub-intervals is 0.000218981752365422"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 10 bins)')

# Case 3: Divided in 20 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.single, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.05))))
spacings.expected <- (n-1)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.single, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_20 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_20
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=18)
p_value <- pchisq(chi_2, df=18, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 20 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 20 sub-intervals is 0.0117020696134169"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 20 bins)')

# Consecutive Pairs
locations.sorted <- sort(locations, decreasing = FALSE)
locations.pairs <- locations.sorted[-length(locations.sorted)]
distance.pairs <- abs(locations.sorted[-1][-1]-locations.pairs[-length(locations.pairs)])
# Histogram of spacings of palindromes in original data and exponential distribution
hist(distance.pairs, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Consecutive Pairs Spacings Distribution Comparison", xlab = "Distance between Consecutive Pairs of Palindromes Locations", ylim = c(0,0.001))
lines(density(distance.pairs, adjust = 2), col = rgb(1,0,0,0.5))
Expo <- rexp(n-2, rate = 1/mean(distance.pairs))
hist(Expo, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Expo, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 4200, y = 0.0005, legend = c("Sample", "Exponential"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Chi-square Goodness of Fit Test
# Case 1: Divided in 7 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.pairs, decreasing = FALSE)
lambda <- 1/mean(distance.pairs)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(0,0.05, 0.1, 0.3, 0.5, 0.7, 0.9,1)))
spacings.expected <- (n-2)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_7 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_7
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=5)
p_value <- pchisq(chi_2, df=5, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 7 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 7 sub-intervals is 4.0192806354887e-05"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Spacings between Palindrome Pairs', main='Plot of Standardized Residual for Locations (divided in 7 bins)')

# Case 2: Divided in 10 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.pairs, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.1))))
spacings.expected <- (n-2)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_10 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_10
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=8)
p_value <- pchisq(chi_2, df=8, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 10 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 10 sub-intervals is 1.68753795541538e-05"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Spacings between Palindrome Pairs', main='Plot of Standardized Residual for Locations (divided in 10 bins)')

# Case 3: Divided in 20 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.pairs, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.05))))
spacings.expected <- (n-2)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_20 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_20
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=18)
p_value <- pchisq(chi_2, df=18, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 20 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 20 sub-intervals is 0.000159225622786541"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type = 'h', ylab = "Standardized Residuals", xlab = "Spacings between Palindrome Pairs", main = "Plot of Standardized Residual for Locations (divided in 20 bins)")

# Consecutive Triplets
locations.sorted <- sort(locations, decreasing = FALSE)
locations.triplets <- locations.sorted[-length(locations.sorted)]
locations.triplets <- locations.triplets[-length(locations.triplets)]
distance.triplets <- abs(locations.sorted[-1][-1][-1]-locations.triplets[-length(locations.triplets)])
# Histogram of spacings of palindromes in original data and exponential distribution
hist(distance.triplets, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Consecutive Triplets Spacings Distribution Comparison", xlab = "Distance between Consecutive Palindromes Triplets", ylim = c(0,0.0004))
lines(density(distance.triplets, adjust = 2), col = rgb(1,0,0,0.5))
Gam <- rgamma(n-2, 2, rate = 1/mean(distance.pairs))
hist(Gam, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Gam, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 5000, y = 0.0003, legend = c("Sample", "Gamma"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Chi-square Goodness of Fit Test (Need to be changed)
# Case 1: Divided in 7 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.triplets, decreasing = FALSE)
lambda <- 2/mean(distance.pairs)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(0,0.05, 0.1, 0.3, 0.5, 0.7, 0.9,1)))
spacings.expected <- (n-3)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_7 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_7
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p = 0.95, df = 5)
p_value <- pchisq(chi_2, df = 5, lower.tail = FALSE)
print(paste("The p_value when the distance is splited into 7 sub-intervals is", p_value))
[1] "The p_value when the distance is splited into 7 sub-intervals is 9.07421505828639e-47"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type = 'h', ylab = "Standardized Residuals", xlab = "Palindrome locations", main = "Plot of Standardized Residual for Locations (divided in 7 bins)")

# Case 2: Divided in 10 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.pairs, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.1))))
spacings.expected <- (n-3)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_10 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_10
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p = 0.95, df = 8)
p_value <- pchisq(chi_2, df = 8, lower.tail = FALSE)
print(paste("The p_value when the distance is splited into 10 sub-intervals is", p_value))
[1] "The p_value when the distance is splited into 10 sub-intervals is 8.252676182357e-37"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type = 'h', ylab = "Standardized Residuals", xlab = "Palindrome locations", main = "Plot of Standardized Residual for Locations (divided in 10 bins)")

# Case 3: Divided in 20 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.pairs, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.05))))
spacings.expected <- (n-3)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_20 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_20
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p = 0.95, df = 18)
p_value <- pchisq(chi_2, df = 18, lower.tail = FALSE)
print(paste("The p_value when the distance is splited into 20 sub-intervals is", p_value))
[1] "The p_value when the distance is splited into 20 sub-intervals is 1.34421275018616e-39"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type = 'h', ylab = "Standardized Residuals", xlab = "Palindrome locations", main = "Plot of Standardized Residual for Locations (divided in 20 bins)")

Scenario 3: Counts
Use graphical methods and more formal statistical tests to examine the counts of palindromes in various regions of the DNA. Split the DNA into nonoverlapping regions of equal length to compare the number of palindomres in an interval to the number of that you would expect from uniform random scatter. The counts for shorter regions will be more variable than those for logner regions. Also, consider classifying the regions according to the number of counts.
regionsplit <- function(n.region, gene, site){
count.int <- table(cut(site, breaks = seq(1, length(gene), length.out=n.region+1), include.lowest=TRUE))
count.vector <- as.vector(count.int)
count.tab <- table(count.vector)
return (count.tab)
}
# Case 1: divided by 40 intervals
n.region <- 40
gene <- seq(1,N)
observed <- as.numeric(regionsplit(n.region, gene, locations))
interval <- as.numeric(names(regionsplit(n.region, gene, locations)))
lambda <- n/n.region
# Histogram of counts of palindromes in original data and poisson distribution
counts.hist <- regionsplit(n.region, gene, locations)
hist(counts.hist, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Counts of Palindrome Distribution Comparison (40 sub-intervals)", xlab = "Counts found per interval", ylim = c(0,0.6))
lines(density(counts.hist, adjust = 2), col = rgb(1,0,0,0.5))
Pois <- rpois(n, lambda)
hist(Pois, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Pois, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 7, y = 0.5, legend = c("Sample", "Poisson"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Chi-sqr Goodness of Fit test
expected <- n.region*exp(-lambda)* lambda**(interval)/factorial(interval)
for (i in c(0:2)){
expect <- n.region*exp(-lambda)* lambda**(i)/factorial(i)
expected[1] <- expected[1]+ expect
}
expect <- n.region*exp(-lambda)* lambda**(11)/factorial(11)
expected[8] <- expected[8]+ expect
expected[10] <- 0
for (i in c(1:12)){
expect <- exp(-lambda)* lambda**(i)/factorial(i)
expected[10] <- expected[10]+ expect
}
expected[10] <- (1-expected[10])*n.region
counts.expected <- c()
counts.interval <- c()
counts.observed <- c()
# Group bins
counts.expected[1] <- sum(expected[1:2])
counts.expected[2] <- sum(expected[3:4])
counts.expected[3] <- sum(expected[5])
counts.expected[4] <- sum(expected[6:7])
counts.expected[5] <- sum(expected[8:10])
counts.observed[1] <- sum(observed[1:2])
counts.observed[2] <- sum(observed[3:4])
counts.observed[3] <- sum(observed[5])
counts.observed[4] <- sum(observed[6:7])
counts.observed[5] <- sum(observed[8:10])
counts.interval[1] <- interval[2]
counts.interval[2] <- interval[4]
counts.interval[3] <- interval[5]
counts.interval[4] <- interval[7]
counts.interval[5] <- interval[7]+1
counts.table40 <- data.frame(counts.interval,counts.observed,counts.expected)
counts.table40
# Chi-square statistic
chi_2 <- sum((counts.observed - counts.expected)^2/counts.expected)
chi2_compare <- qchisq(p = 0.95, df = 3)
p_value <- pchisq(chi_2, df = 3, lower.tail = FALSE)
print(paste("The p_value when the distance is splited into 40 sub-intervals is", p_value))
[1] "The p_value when the distance is splited into 40 sub-intervals is 0.365205436984496"
## Visualization of the Residual
Residuals <- (counts.observed - counts.expected) / sqrt(counts.expected)
plot(Residuals, type = 'h', ylab = "Standardized Residuals", xlab = "Palindrome counts", main = "Plot of Standardized Residual for Counts (divided in 40 sub-intervals)")

# Case 2: divided by 60 intervals
n.region <- 60
gene <- seq(1,N)
observed <- as.numeric(regionsplit(n.region, gene, locations))
interval <- as.numeric(names(regionsplit(n.region, gene, locations)))
lambda <- n/n.region
# Histogram of counts of palindromes in original data and poisson distribution
counts.hist <- regionsplit(n.region, gene, locations)
hist(counts.hist, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Counts of Palindrome Distribution Comparison (60 sub-intervals)", xlab = "Counts found per interval", ylim = c(0,0.6))
lines(density(counts.hist, adjust = 2), col = rgb(1,0,0,0.5))
Pois <- rpois(n, lambda)
hist(Pois, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Pois, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 7, y = 0.5, legend = c("Sample", "Poisson"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Chi-sqr Goodness of Fit test
expected <- n.region*exp(-lambda)* lambda**(interval)/factorial(interval)
expect <- n.region*exp(-lambda)* lambda**(0)/factorial(0)
expected[1] <- expected[1]+ expect
for (i in c(10:11)){
expect <- n.region*exp(-lambda)* lambda**(i)/factorial(i)
expected[9] <- expected[9]+ expect
}
expected[11] <- 0
for (i in c(1:12)){
expect <- exp(-lambda)* lambda**(i)/factorial(i)
expected[11] <- expected[11]+ expect
}
expected[11] <- (1-expected[11])*n.region
counts.expected <- c()
counts.interval <- c()
counts.observed <- c()
# Group bins
counts.expected[1] <- sum(expected[1:2])
counts.expected[2:6] <- expected[3:7]
counts.expected[7] <- sum(expected[8:11])
counts.observed[1] <- sum(observed[1:2])
counts.observed[2:6] <- observed[3:7]
counts.observed[7] <- sum(observed[8:11])
counts.interval[1] <- interval[2]
counts.interval[2:6] <- interval[3:7]
counts.interval[7] <- interval[7]+1
counts.table60 <- data.frame(counts.interval,counts.observed,counts.expected)
counts.table60
# Chi-square statistic
chi_2 <- sum((counts.observed - counts.expected)^2/counts.expected)
chi2_compare <- qchisq(p = 0.95, df = 5)
p_value <- pchisq(chi_2, df = 5, lower.tail = FALSE)
print(paste("The p_value when the distance is splited into 60 sub-intervals is", p_value))
[1] "The p_value when the distance is splited into 60 sub-intervals is 0.406748395085584"
## Visualization of the Residual
Residuals <- (counts.observed - counts.expected) / sqrt(counts.expected)
plot(Residuals, type = 'h', ylab = "Standardized Residuals", xlab = "Palindrome counts", main = "Plot of Standardized Residual for Counts (divided in 60 sub-intervals)")

# Case 3: divided by 80 intervals
n.region <- 80
gene <- seq(1,N)
observed <- as.numeric(regionsplit(n.region, gene, locations))
interval <- as.numeric(names(regionsplit(n.region, gene, locations)))
lambda <- n/n.region
# Histogram of counts of palindromes in original data and poisson distribution
counts.hist <- regionsplit(n.region, gene, locations)
hist(counts.hist, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Counts of Palindrome Distribution Comparison (80 sub-intervals)", xlab = "Counts found per interval", ylim = c(0,0.6))
lines(density(counts.hist, adjust = 2), col = rgb(1,0,0,0.5))
Pois <- rpois(n, lambda)
hist(Pois, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Pois, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 7, y = 0.5, legend = c("Sample", "Poisson"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Chi-sqr Goodness of Fit test
expected <- n.region*exp(-lambda)* lambda**(interval)/factorial(interval)
for (i in c(8:9)){
expect <- n.region*exp(-lambda)* lambda**(i)/factorial(i)
expected[9] <- expected[9]+ expect
}
expected[10] <- 0
for (i in c(1:10)){
expect <- exp(-lambda)* lambda**(i)/factorial(i)
expected[10] <- expected[10]+ expect
}
expected[10] <- (1-expected[10])*n.region
counts.expected <- c()
counts.interval <- c()
counts.observed <- c()
# Group bins
counts.expected[1] <- sum(expected[1:2])
counts.expected[2:6] <- expected[3:7]
counts.expected[7] <- sum(expected[8:10])
counts.observed[1] <- sum(observed[1:2])
counts.observed[2:6] <- observed[3:7]
counts.observed[7] <- sum(observed[8:10])
counts.interval[1] <- interval[2]
counts.interval[2:6] <- interval[3:7]
counts.interval[7] <- interval[7]+1
counts.table60 <- data.frame(counts.interval,counts.observed,counts.expected)
counts.table60
# Chi-square statistic
chi_2 <- sum((counts.observed - counts.expected)^2/counts.expected)
chi2_compare <- qchisq(p = 0.95, df = 5)
p_value <- pchisq(chi_2, df = 5, lower.tail = FALSE)
print(paste("The p_value when the distance is splited into 60 sub-intervals is", p_value))
[1] "The p_value when the distance is splited into 60 sub-intervals is 0.868215562053925"
## Visualization of the Residual
Residuals <- (counts.observed - counts.expected) / sqrt(counts.expected)
plot(Residuals, type = 'h', ylab = "Standardized Residuals", xlab = "Palindrome counts", main = "Plot of Standardized Residual for Counts (divided in 80 sub-intervals)")

LS0tCnRpdGxlOiAnQ0FTRSBTVFVEWSAzOiBTRUFSQ0ggRk9SIFRIRSBVTlVTVUFMIENMVVNURVIgSU4gVEhFIFBBTElORFJPTUVTJwpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKIyMgUXVlc3Rpb24KSW4gdGhpcyBwYXBlciwgd2Ugd2lsbCBzZWFyY2ggZm9yIHVudXN1YWwgY2x1c3RlcnMgb2YgY29tcGxlbWVudGFyeSBwYWxpbmRyb21lcy4gVGhlIG92ZXJhcmNoaW5nIHJlc2VhcmNoIHF1ZXN0aW9uIGlzOiDigJxIb3cgZG8gd2UgZmluZCBjbHVzdGVycyBvZiBwYWxpbmRyb21lcz8gSG93IGRvIHdlIGRldGVybWluZSB3aGV0aGVyIGEgY2x1c3RlciBpcyBqdXN0IGEgY2hhbmNlIG9jY3VycmVuY2Ugb3IgYSBwb3RlbnRpYWwgcmVwbGljYXRpb24gc2l0ZT8gQmFzZWQgb24gb3VyIGFuYWx5c2lzLCB3ZSB3aWxsIHRoZW4gcHJvdmlkZSByZWNvbW1lbmRhdGlvbnMgdG8gYmlvbG9naXN0cyB3aG8gYXJlIGFib3V0IHRvIHN0YXJ0IGV4cGVyaW1lbnRhbGx5IHNlYXJjaGluZyBmb3IgdGhlIG9yaWdpbiBvZiByZXBsaWNhdGlvbi4KCgojIyBTZXR1cApgYGB7cn0KbG9jYXRpb25zIDwtIHJlYWQudGFibGUoJ2hjbXYtMjVrZ2puMS0xcmZydGtjLnR4dCcsIGhlYWRlcj1UUlVFKSRsb2NhdGlvbiAgIyBPcmlnaW5hbApoZWFsdGggPC0gcmVhZC5jc3YoJ1JBV19EQVRBLTJpd2N6bm4tMmtyMnh3MC5jc3YnLCBoZWFkZXI9VFJVRSkgICMgQWRkaXRpb25hbAoKTiA8LSAyMjkzNTQgICMgQmFzZSBwYWlycwpuIDwtIDI5NiAgIyBQYWxpbmRyb21lcwpgYGAKCgojIyBTY2VuYXJpbyAxOiBSYW5kb20gU2NhdHRlcgpUbyBiZWdpbiwgcHVyc3VlIHRoZSBwb2ludCBvZiB2aWV3IHRoYXQgc3RydWN0dXJlIGluIHRoZSBkYXRhIGlzIGluZGljYXRlZCBieSBkZXBhcnR1cmVzIGZyb20gYSB1bmlmb3JtIHNjYXR0ZXIgb2YgcGFsaW5kcm9tZXMgYWNyb3NzIHRoZSBETkEuCgoqT2YgY291cnNlLCBhIHJhbmRvbSB1bmlmb3JtIHNjYXR0ZXIgZG9lcyB0aGF0IG1lYW4gdGhhdCBwYWxpbmRyb21lcyB3aWxsIGJlIGVxdWFsbHkgc3BhY2VkIGFzIG1pbGVzdG9uZXMgb24gYSBmcmVld2F5LiBUaGVyZSB3aWxsIGJlIHNvbWUgZ2FwcyBvbiB0aGUgRE5BIHdoZXJlIG5vIHBhbGluZHJvbWVzIG9jY3VyLCBhbmQgdGhlcmUgd2lsbCBiZSBzb21lIGNsdW1waW5nIHRvZ2V0aGVyIG9mIHBhbGluZHJvbWVzLioKClRvIGxvb2sgZm9yIHN0cnVjdHVyZSBleGFtaW5lIHRoZSBsb2NhdGlvbnMgb2YgdGhlIHBhbGluZHJvbWVzLCB0aGUgc3BhY2luZyBiZXR3ZWVuIHBhbGluZHJvbWVzLCBhbmQgdGhlIGNvdW50cyBvZiBwYWxpbmRyb21lcyBpbiBub24gb3ZlcmxhcHBpbmcgcmVnaW9ucyBvZiB0aGUgRE5BLiBPbmUgc3RhcnRpbmcgcGxhY2UgbWlnaHQgYmUgdG8gc2VlIGZpcnN0IGhvdyByYW5kb20gc2NhdHRlciBsb29rcyBieSB1c2luZyBhIGNvbXB1dGVyIHRvIHNpbXVsYXRlIGl0LgoKKkEgY29tcHV0ZXIgY2FuIHNpbXVsYXRlIDI5NiBwYWxpbmRyb21lIHNpdGVzIGNob3NlbiBhdCByYW5kb20gYWxvbmcgYSBETkEgc2VxdWVuY2Ugb2YgMjI5LDM1NCBiYXNlcyB1c2luZyBhIHBzZXVkbyByYW5kb20gbnVtYmVyIGdlbmVyYXRvci4gV2hlbiB0aGlzIGlzIGRvbmUgc2V2ZXJhbCB0aW1lcywgYnkgbWFraW5nIHNlbGxlciBzZXRzIG9mIHNpbXVsYXRlZCBwYWxpbmRyb21lIGxvY2F0aW9ucywgdGhlbiB0aGUgcmVhbCBkYXRhIGNhbiBiZSBjb21wYXJlZCB0byB0aGUgc2ltdWxhdGVkIGRhdGEuKgpgYGB7cn0Kc2V0LnNlZWQoMCkKY29sb3IgPC0gJ3JlZCcKCiMgR2VuZXJhdGUgMyBzYW1wbGVzIGZyb20gdGhlIHVuaWZvcm0gZGlzdHJpYnV0aW9uIHdpdGggdGhlIHNhbWUgc2l6ZSBhbmQgYm91bmRzIGFzIG91ciBkYXRhCnNhbXBsZXM9bGlzdChzb3J0KHJ1bmlmKG4sIG1pbj0wLCBtYXg9TikpLCBzb3J0KHJ1bmlmKG4sIG1pbj0wLCBtYXg9TikpLCBzb3J0KHJ1bmlmKG4sIG1pbj0wLCBtYXg9TikpKQoKIyBEb3QgcGxvdCBvZiBsb2NhdGlvbnMgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgdW5pZm9ybSBzY2F0dGVyCnRpdGxlMSA8LSAnTG9jYXRpb25zIG9mIFBhbGluZHJvbWVzJwp0aXRsZTIgPC0gYyh0aXRsZTEsJyhTaW11bGF0ZWQpJykKeC5heGlzIDwtICdCYXNlIFBhaXInCnN5bWJvbCA8LSAzCnN0cmlwY2hhcnQobG9jYXRpb25zLCBwY2g9c3ltYm9sLCBjb2w9Y29sb3IsIG1haW49dGl0bGUxLCB4bGFiPXguYXhpcykKZm9yIChzYW1wbGUgaW4gc2FtcGxlcykgewogIHN0cmlwY2hhcnQoc2FtcGxlLCBwY2g9c3ltYm9sLCBtYWluPXRpdGxlMiwgeGxhYj14LmF4aXMpCn0KCiMgQWRkaXRpb25hbCBkb3QgcGxvdCBvZiBsb2NhdGlvbnMgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgdW5pZm9ybSBzY2F0dGVyCmRvdGNoYXJ0KGxvY2F0aW9ucywgY29sb3I9Y29sb3IsIG1haW49dGl0bGUxLCB4bGFiPXguYXhpcykKZm9yIChzYW1wbGUgaW4gc2FtcGxlcykgewogIGRvdGNoYXJ0KHNhbXBsZSwgbWFpbj10aXRsZTIsIHhsYWI9eC5heGlzKQp9CgojIEhpc3RvZ3JhbSBvZiBsb2NhdGlvbnMgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgdW5pZm9ybSBzY2F0dGVyCmJpbnMgPC0gMzUKaGlzdChsb2NhdGlvbnMsIGNvbD1jb2xvciwgYnJlYWtzPWJpbnMsIG1haW49dGl0bGUxLCB4bGFiPXguYXhpcykKZm9yIChzYW1wbGUgaW4gc2FtcGxlcykgewogIGhpc3Qoc2FtcGxlLCBicmVha3M9YmlucywgbWFpbj10aXRsZTIsIHhsYWI9eC5heGlzKQp9CgoKCiMgU2NhdHRlcnBsb3Qgb2Ygc3BhY2luZyBiZXR3ZWVuIGNvbnNlY3V0aXZlIHBhbGluZHJvbWVzCnRpdGxlMSA8LSAnU3BhY2luZyBiZXR3ZWVuIENvbnNlY3V0aXZlIFBhbGluZHJvbWVzJwp0aXRsZTIgPC0gYyh0aXRsZTEsJyhTaW11bGF0ZWQpJykKeC5heGlzIDwtICdCYXNlIFBhaXIgTG9jYXRpb24nCnkuYXhpcyA8LSAnRGlzdGFuY2UgKEJhc2UgUGFpcnMpIGZyb20gUHJldmlvdXMgUGFsaW5kcm9tZScKeS5yYW5nZSA8LSBjKDAsNTAwMCkKcGxvdChsb2NhdGlvbnNbLTFdLCBkaWZmKGxvY2F0aW9ucyksIGNvbD1jb2xvciwgeWxpbT15LnJhbmdlLCBtYWluPXRpdGxlMSwgeGxhYj14LmF4aXMsIHlsYWI9eS5heGlzKQpmb3IgKHNhbXBsZSBpbiBzYW1wbGVzKSB7CiAgcGxvdChzYW1wbGVbLTFdLCBkaWZmKHNhbXBsZSksIHlsaW09eS5yYW5nZSwgbWFpbj10aXRsZTIsIHhsYWI9eC5heGlzLCB5bGFiPXkuYXhpcykKfQoKCgojIEhpc3RvZ3JhbSBvZiBjb3VudHMgb2YgcGFsaW5kcm9tZXMgaW4gbm9uLW92ZXJsYXBwaW5nIHJlZ2lvbnMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgdW5pZm9ybSBzY2F0dGVyCmludGVydmFsLmxlbmd0aCA8LSAyNTAwCnRpdGxlMSA8LSBwYXN0ZSgnTnVtYmVyIG9mIFBhbGluZHJvbWVzIGluIE5vbi1PdmVybGFwcGluZyBSZWdpb25zIG9mIExlbmd0aCcsIGludGVydmFsLmxlbmd0aCkKdGl0bGUyIDwtIGModGl0bGUxLCcoU2ltdWxhdGVkKScpCnguYXhpcyA8LSAnTnVtYmVyIG9mIFBhbGluZHJvbWVzJwpiaW5zIDwtIHNlcSgwLDIwLDEpCmhpc3QoYXMudmVjdG9yKHRhYmxlKGN1dChsb2NhdGlvbnMsIGJyZWFrcz1zZXEoMCxOLGludGVydmFsLmxlbmd0aCksIGluY2x1ZGUubG93ZXN0PVRSVUUpKSksIGJyZWFrcz1iaW5zLCBjb2w9Y29sb3IsIG1haW49dGl0bGUxLCB4bGFiPXguYXhpcykKZm9yIChzYW1wbGUgaW4gc2FtcGxlcykgewogIGhpc3QoYXMudmVjdG9yKHRhYmxlKGN1dChzYW1wbGUsIGJyZWFrcz1zZXEoMCxOLGludGVydmFsLmxlbmd0aCksIGluY2x1ZGUubG93ZXN0PVRSVUUpKSksIGJyZWFrcz1iaW5zLCBtYWluPXRpdGxlMiwgeGxhYj14LmF4aXMpCn0KYGBgCgoKIyMgU2NlbmFyaW8gMjogTG9jYXRpb25zIGFuZCBTcGFjaW5ncwpVc2UgZ3JhcGhpY2FsIG1ldGhvZHMgdG8gZXhhbWluZSB0aGUgc3BhY2luZ3MgYmV0d2VlbiBjb25zZWN1dGl2ZSBwYWxpbmRyb21lcyBhbmQgc3VtIG9mIGNvbnNlY3V0aXZlIHBhaXJzLCB0cmlwbGV0cywgZXRjLCBzcGFjaW5ncy4gQ29tcGFyZSB3aGF0IHlvdSBmaW5kIHRvIHdoYXQgeW91IHdvdWxkIGV4cGVjdCB0byBmaW5kIGluIGEgcmFuZG9tIHNjYXR0ZXIuIEFsc28sIHVzZSBncmFwaGljYWwgbWV0aG9kcyB0byBjb21wYXJlIGxvY2F0aW9ucyBvZiB0aGUgcGFsaW5kcm9tZXMuCmBgYHtyfQojIENoaS1zcXVhcmUgR29vZG5lc3Mgb2YgRml0IFRlc3QKIyBDYXNlIDE6IGsobnVtYmVyIG9mIHN1Yi1pbnRlcnZhbHMpPTIwCmsgPC0gMjAKbG9jYXRpb25zLmV4cGVjdGVkIDwtIG4vawp0YWIgPC0gdGFibGUoY3V0KGxvY2F0aW9ucywgYnJlYWtzPXNlcSgwLCBOLCBsZW5ndGgub3V0PWsrMSksIGluY2x1ZGUubG93ZXN0PVRSVUUpKQpsb2NhdGlvbnMub2JzZXJ2ZWQgPC0gYXMudmVjdG9yKHRhYikKY2hpXzIgPC0gc3VtKChsb2NhdGlvbnMub2JzZXJ2ZWQgLSBsb2NhdGlvbnMuZXhwZWN0ZWQpXjIvbG9jYXRpb25zLmV4cGVjdGVkKQpjaGkyX2NvbXBhcmUgPC0gcWNoaXNxKHA9MC45NSwgZGY9MTkpCnBfdmFsdWUgPC0gcGNoaXNxKGNoaV8yLCBkZj0xOSwgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQoY2F0KCdcbldoZW4gY29uZHVjdGluZyBjaGlfc3F1YXJlIEdvb2RuZXNzIG9mIGZpdCB0ZXN0IGNvbXBhcmluZyBsb2NhdGlvbnMoZGl2aWRlZCBpbiAyMCBzdWItaW50ZXJ2YWxzKSBhZ2FpbnN0IHVuaWZvcm0gZGlzdHJpYnV0aW9uXG4nKSkKcHJpbnQocGFzdGUoJ1RoZSB2YWx1ZSBvZiBjaGlfc3F1YXJlIHN0YXRpc3RpYyBpcycsIGNoaV8yKSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIGlzJywgcF92YWx1ZSkpCgojIyBWaXN1YWxpemF0aW9uIG9mIHRoZSBSZXNpZHVhbApSZXNpZHVhbHMgPC0gKGxvY2F0aW9ucy5vYnNlcnZlZCAtIGxvY2F0aW9ucy5leHBlY3RlZCkgLyBzcXJ0KGxvY2F0aW9ucy5leHBlY3RlZCkKcGxvdChSZXNpZHVhbHMsIHR5cGU9J2gnLCB5bGFiPSdTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzJywgeGxhYj0nUGFsaW5kcm9tZSBsb2NhdGlvbnMnLCBtYWluPSdQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgTG9jYXRpb25zIChkaXZpZGVkIGluIDIwIHN1Yi1pbnRlcnZhbHMpJykKCiMgQ2FzZSAyOiBrKG51bWJlciBvZiBzdWItaW50ZXJ2YWxzKT0zMAprIDwtIDMwCmxvY2F0aW9ucy5leHBlY3RlZCA8LSBuL2sKdGFiIDwtIHRhYmxlKGN1dChsb2NhdGlvbnMsIGJyZWFrcz1zZXEoMCwgTiwgbGVuZ3RoLm91dD1rKzEpLCBpbmNsdWRlLmxvd2VzdD1UUlVFKSkKbG9jYXRpb25zLm9ic2VydmVkIDwtIGFzLnZlY3Rvcih0YWIpCmNoaV8yIDwtIHN1bSgobG9jYXRpb25zLm9ic2VydmVkIC0gbG9jYXRpb25zLmV4cGVjdGVkKV4yL2xvY2F0aW9ucy5leHBlY3RlZCkKY2hpMl9jb21wYXJlIDwtIHFjaGlzcShwPTAuOTUsIGRmPTI5KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9MjksIGxvd2VyLnRhaWw9RkFMU0UpCnByaW50KGNhdCgnXG5XaGVuIGNvbmR1Y3RpbmcgY2hpX3NxdWFyZSBHb29kbmVzcyBvZiBmaXQgdGVzdCBjb21wYXJpbmcgbG9jYXRpb25zKGRpdmlkZWQgaW4gMzAgc3ViLWludGVydmFscykgYWdhaW5zdCB1bmlmb3JtIGRpc3RyaWJ1dGlvblxuJykpCnByaW50KHBhc3RlKCdUaGUgdmFsdWUgb2YgY2hpX3NxdWFyZSBzdGF0aXN0aWMgaXMnLCBjaGlfMikpCnByaW50KHBhc3RlKCdUaGUgcF92YWx1ZSBpcycsIHBfdmFsdWUpKQoKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChsb2NhdGlvbnMub2JzZXJ2ZWQgLSBsb2NhdGlvbnMuZXhwZWN0ZWQpIC8gc3FydChsb2NhdGlvbnMuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlPSdoJywgeWxhYj0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHhsYWI9J1BhbGluZHJvbWUgbG9jYXRpb25zJywgbWFpbj0nUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWwgZm9yIExvY2F0aW9ucyAoZGl2aWRlZCBpbiAzMCBzdWItaW50ZXJ2YWxzKScpCgojIENhc2UgMzogayhudW1iZXIgb2Ygc3ViLWludGVydmFscyk9NjAKayA8LSA2MApsb2NhdGlvbnMuZXhwZWN0ZWQgPC0gbi9rCnRhYiA8LSB0YWJsZShjdXQobG9jYXRpb25zLCBicmVha3M9c2VxKDAsIE4sIGxlbmd0aC5vdXQ9aysxKSwgaW5jbHVkZS5sb3dlc3Q9VFJVRSkpCmxvY2F0aW9ucy5vYnNlcnZlZCA8LSBhcy52ZWN0b3IodGFiKQpjaGlfMiA8LSBzdW0oKGxvY2F0aW9ucy5vYnNlcnZlZCAtIGxvY2F0aW9ucy5leHBlY3RlZCleMi9sb2NhdGlvbnMuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj01OSkKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmPTU5LCBsb3dlci50YWlsPUZBTFNFKQpwcmludChjYXQoJ1xuV2hlbiBjb25kdWN0aW5nIGNoaV9zcXVhcmUgR29vZG5lc3Mgb2YgZml0IHRlc3QgY29tcGFyaW5nIGxvY2F0aW9ucyhkaXZpZGVkIGluIDYwIHN1Yi1pbnRlcnZhbHMpIGFnYWluc3QgdW5pZm9ybSBkaXN0cmlidXRpb25cbicpKQpwcmludChwYXN0ZSgnVGhlIHZhbHVlIG9mIGNoaV9zcXVhcmUgc3RhdGlzdGljIGlzJywgY2hpXzIpKQpwcmludChwYXN0ZSgnVGhlIHBfdmFsdWUgaXMnLCBwX3ZhbHVlKSkKCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAobG9jYXRpb25zLm9ic2VydmVkIC0gbG9jYXRpb25zLmV4cGVjdGVkKSAvIHNxcnQobG9jYXRpb25zLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZT0naCcsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLCB4bGFiPSdQYWxpbmRyb21lIGxvY2F0aW9ucycsIG1haW49J1Bsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gNjAgc3ViLWludGVydmFscyknKQoKIyBIaXN0b2dyYW0gb2YgbG9jYXRpb25zIG9mIHBhbGluZHJvbWVzIGluIG9yaWdpbmFsIGRhdGEgYW5kIHVuaWZvcm0gc2NhdHRlcgpzYW1wbGUgPC0gcnVuaWYobiwgbWluPTAsIG1heD1OKQp0aXRsZSA8LSAnTG9jYXRpb25zIG9mIFBhbGluZHJvbWVzIChPcmlnaW5hbCB2cy4gU2ltdWxhdGVkKScKeC5heGlzIDwtICdCYXNlIFBhaXInCmJpbnMgPC0gMzUKaGlzdChsb2NhdGlvbnMsIGJyZWFrcz1iaW5zLCBwcm9iYWJpbGl0eT1UUlVFLCBjb2w9cmdiKDEsMCwwLDAuNSksIG1haW49dGl0bGUsIHhsYWI9eC5heGlzKQpsaW5lcyhkZW5zaXR5KGxvY2F0aW9ucywgYWRqdXN0PTIpLCBjb2w9MikKaGlzdChzYW1wbGUsIGJyZWFrcz1iaW5zLCBwcm9iYWJpbGl0eT1UUlVFLCBjb2w9cmdiKDAsMCwxLDAuNSksIGFkZD1UUlVFKQpsaW5lcyhkZW5zaXR5KHNhbXBsZSwgYWRqdXN0PTIpLCBjb2w9NCkKbGVnZW5kKCd0b3ByaWdodCcsIGxlZ2VuZD1jKCdPcmlnaW5hbCcsICdVbmlmb3JtJyksIGx0eT1jKDEsMSksIGNvbD1jKHJnYigxLDAsMCwwLjUpLCByZ2IoMCwwLDEsMC41KSkpCgojIFNpbmdsZSBQYWxpbmRyb21lIFNwYWNpbmcKbG9jYXRpb25zLnNvcnRlZCA9IHNvcnQobG9jYXRpb25zLCBkZWNyZWFzaW5nID0gRkFMU0UpCmRpc3RhbmNlLnNpbmdsZSA8LSBhYnMobG9jYXRpb25zLnNvcnRlZFstMV0tbG9jYXRpb25zLnNvcnRlZFstbGVuZ3RoKGxvY2F0aW9ucy5zb3J0ZWQpXSkKCiMgSGlzdG9ncmFtIG9mIHNwYWNpbmdzIG9mIHBhbGluZHJvbWVzIGluIG9yaWdpbmFsIGRhdGEgYW5kIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbgpoaXN0KGRpc3RhbmNlLnNpbmdsZSwgYnJlYWtzPSAxNSwgY29sID0gcmdiKDEsMCwwLDAuNSksIHByb2JhYmlsaXR5ID0gVFJVRSwgbWFpbiA9ICJDb25zZWN1dGl2ZSBwYWxpbmRyb21lIFNwYWNpbmdzIERpc3RyaWJ1dGlvbiBDb21wYXJpc29uIiwgeGxhYiA9ICJEaXN0YW5jZSBiZXR3ZWVuIENvbnNlY3V0aXZlIFBhbGluZHJvbWVzIiwgeWxpbSA9IGMoMCwwLjAwMSkpCmxpbmVzKGRlbnNpdHkoZGlzdGFuY2Uuc2luZ2xlLCBhZGp1c3QgPSAyKSwgY29sID0gcmdiKDEsMCwwLDAuNSkpCkV4cG8gPC0gcmV4cChuLTEsIHJhdGUgPSAxL21lYW4oZGlzdGFuY2Uuc2luZ2xlKSkKaGlzdChFeHBvLCBicmVha3MgPSAxNSwgY29sID0gcmdiKDAsMCwxLDAuNSksIHByb2JhYmlsaXR5ID0gVFJVRSwgYWRkID0gVFJVRSkKbGluZXMoZGVuc2l0eShFeHBvLCBhZGp1c3QgPSAyKSwgY29sID0gcmdiKDAsMCwxLDAuNSkpCmxlZ2VuZCh4ID0gNDIwMCwgeSA9IDAuMDAwOSwgbGVnZW5kID0gYygiU2FtcGxlIiwgIkV4cG9uZW50aWFsIiksIGx0eSA9IGMoMSwxKSwgY29sID0gYyhyZ2IoMSwwLDAsMC41KSwgcmdiKDAsMCwxLDAuNSkpKQoKIyBDaGktc3F1YXJlIEdvb2RuZXNzIG9mIEZpdCBUZXN0CiMgQ2FzZSAxOiBEaXZpZGVkIGluIDcgaW50ZXJ2YWxzCiMgQ29uc3RydWN0IGV4cGVjdGVkIG51bWJlciBvZiBpbnRlcnZhbHMKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gc29ydChkaXN0YW5jZS5zaW5nbGUsIGRlY3JlYXNpbmcgPSBGQUxTRSkKbGFtYmRhIDwtIDEvbWVhbihkaXN0YW5jZS5zaW5nbGUpCnNwYWNpbmdzLmludGVydmFscyA8LSBhcy5udW1lcmljKHF1YW50aWxlKHNwYWNpbmdzLm9ic2VydmVkLCBwcm9icyA9IGMoMCwwLjA1LCAwLjEsIDAuMywgMC41LCAwLjcsIDAuOSwxKSkpCgpzcGFjaW5ncy5leHBlY3RlZCA8LSAobi0xKSooZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy1sZW5ndGgoc3BhY2luZ3MuaW50ZXJ2YWxzKV0pLWV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stMV0pKQpzcGFjaW5ncy5leHBlY3RlZFtsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpXSA8LSBuLXN1bShzcGFjaW5ncy5leHBlY3RlZFsxOmxlbmd0aChzcGFjaW5ncy5leHBlY3RlZCktMV0pCnNwYWNpbmdzLm9ic2VydmVkIDwtIGFzLm51bWVyaWModGFibGUoY3V0KGRpc3RhbmNlLnNpbmdsZSwgYnJlYWtzPXNwYWNpbmdzLmludGVydmFscywgaW5jbHVkZS5sb3dlc3Q9VFJVRSkpKQpjb250aW5nZW5jeV83IDwtIGRhdGEuZnJhbWUoc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSxzcGFjaW5ncy5vYnNlcnZlZCxzcGFjaW5ncy5leHBlY3RlZCkKY29udGluZ2VuY3lfNwoKY2hpXzIgPC0gc3VtKChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKV4yL3NwYWNpbmdzLmV4cGVjdGVkKQpjaGkyX2NvbXBhcmUgPC0gcWNoaXNxKHA9MC45NSwgZGY9NSkKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmPTUsIGxvd2VyLnRhaWw9RkFMU0UpCnByaW50KHBhc3RlKCdUaGUgcF92YWx1ZSB3aGVuIHRoZSBkaXN0YW5jZSBpcyBzcGxpdGVkIGludG8gNyBzdWItaW50ZXJ2YWxzIGlzJywgcF92YWx1ZSkpCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCkgLyBzcXJ0KHNwYWNpbmdzLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZT0naCcsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLCB4bGFiPSdQYWxpbmRyb21lIGxvY2F0aW9ucycsIG1haW49J1Bsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gNyBiaW5zKScpCgojIENhc2UgMjogRGl2aWRlZCBpbiAxMCBpbnRlcnZhbHMKIyBDb25zdHJ1Y3QgZXhwZWN0ZWQgbnVtYmVyIG9mIGludGVydmFscwpzcGFjaW5ncy5vYnNlcnZlZCA8LSBzb3J0KGRpc3RhbmNlLnNpbmdsZSwgZGVjcmVhc2luZyA9IEZBTFNFKQpzcGFjaW5ncy5pbnRlcnZhbHMgPC0gYXMubnVtZXJpYyhxdWFudGlsZShzcGFjaW5ncy5vYnNlcnZlZCwgcHJvYnMgPSBjKHNlcSgwLDEsIGJ5ID0gMC4xKSkpKQoKc3BhY2luZ3MuZXhwZWN0ZWQgPC0gKG4tMSkqKGV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stbGVuZ3RoKHNwYWNpbmdzLmludGVydmFscyldKS1leHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLTFdKSkKc3BhY2luZ3MuZXhwZWN0ZWRbbGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKV0gPC0gbi1zdW0oc3BhY2luZ3MuZXhwZWN0ZWRbMTpsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpLTFdKQpzcGFjaW5ncy5vYnNlcnZlZCA8LSBhcy5udW1lcmljKHRhYmxlKGN1dChkaXN0YW5jZS5zaW5nbGUsIGJyZWFrcyA9IHNwYWNpbmdzLmludGVydmFscywgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkpCmNvbnRpbmdlbmN5XzEwIDwtIGRhdGEuZnJhbWUoc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSxzcGFjaW5ncy5vYnNlcnZlZCxzcGFjaW5ncy5leHBlY3RlZCkKY29udGluZ2VuY3lfMTAKCmNoaV8yIDwtIHN1bSgoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCleMi9zcGFjaW5ncy5leHBlY3RlZCkKY2hpMl9jb21wYXJlIDwtIHFjaGlzcShwPTAuOTUsIGRmPTgpCnBfdmFsdWUgPC0gcGNoaXNxKGNoaV8yLCBkZj04LCBsb3dlci50YWlsPUZBTFNFKQpwcmludChwYXN0ZSgnVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDEwIHN1Yi1pbnRlcnZhbHMgaXMnLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKSAvIHNxcnQoc3BhY2luZ3MuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlPSdoJywgeWxhYj0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHhsYWI9J1BhbGluZHJvbWUgbG9jYXRpb25zJywgbWFpbj0nUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWwgZm9yIExvY2F0aW9ucyAoZGl2aWRlZCBpbiAxMCBiaW5zKScpCgojIENhc2UgMzogRGl2aWRlZCBpbiAyMCBpbnRlcnZhbHMKIyBDb25zdHJ1Y3QgZXhwZWN0ZWQgbnVtYmVyIG9mIGludGVydmFscwpzcGFjaW5ncy5vYnNlcnZlZCA8LSBzb3J0KGRpc3RhbmNlLnNpbmdsZSwgZGVjcmVhc2luZyA9IEZBTFNFKQpzcGFjaW5ncy5pbnRlcnZhbHMgPC0gYXMubnVtZXJpYyhxdWFudGlsZShzcGFjaW5ncy5vYnNlcnZlZCwgcHJvYnMgPSBjKHNlcSgwLDEsIGJ5ID0gMC4wNSkpKSkKCnNwYWNpbmdzLmV4cGVjdGVkIDwtIChuLTEpKihleHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLWxlbmd0aChzcGFjaW5ncy5pbnRlcnZhbHMpXSktZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSkpCnNwYWNpbmdzLmV4cGVjdGVkW2xlbmd0aChzcGFjaW5ncy5leHBlY3RlZCldIDwtIG4tc3VtKHNwYWNpbmdzLmV4cGVjdGVkWzE6bGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKS0xXSkKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyh0YWJsZShjdXQoZGlzdGFuY2Uuc2luZ2xlLCBicmVha3MgPSBzcGFjaW5ncy5pbnRlcnZhbHMsIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpKQoKY29udGluZ2VuY3lfMjAgPC0gZGF0YS5mcmFtZShzcGFjaW5ncy5pbnRlcnZhbHNbLTFdLHNwYWNpbmdzLm9ic2VydmVkLHNwYWNpbmdzLmV4cGVjdGVkKQpjb250aW5nZW5jeV8yMAoKY2hpXzIgPC0gc3VtKChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKV4yL3NwYWNpbmdzLmV4cGVjdGVkKQpjaGkyX2NvbXBhcmUgPC0gcWNoaXNxKHA9MC45NSwgZGY9MTgpCnBfdmFsdWUgPC0gcGNoaXNxKGNoaV8yLCBkZj0xOCwgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIHdoZW4gdGhlIGRpc3RhbmNlIGlzIHNwbGl0ZWQgaW50byAyMCBzdWItaW50ZXJ2YWxzIGlzJywgcF92YWx1ZSkpCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCkgLyBzcXJ0KHNwYWNpbmdzLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZT0naCcsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLCB4bGFiPSdQYWxpbmRyb21lIGxvY2F0aW9ucycsIG1haW49J1Bsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gMjAgYmlucyknKQoKIyBDb25zZWN1dGl2ZSBQYWlycwpsb2NhdGlvbnMuc29ydGVkIDwtICBzb3J0KGxvY2F0aW9ucywgZGVjcmVhc2luZyA9IEZBTFNFKQpsb2NhdGlvbnMucGFpcnMgPC0gbG9jYXRpb25zLnNvcnRlZFstbGVuZ3RoKGxvY2F0aW9ucy5zb3J0ZWQpXQpkaXN0YW5jZS5wYWlycyA8LSBhYnMobG9jYXRpb25zLnNvcnRlZFstMV1bLTFdLWxvY2F0aW9ucy5wYWlyc1stbGVuZ3RoKGxvY2F0aW9ucy5wYWlycyldKQoKIyBIaXN0b2dyYW0gb2Ygc3BhY2luZ3Mgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uCmhpc3QoZGlzdGFuY2UucGFpcnMsIGJyZWFrcz0gMTUsIGNvbCA9IHJnYigxLDAsMCwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAiQ29uc2VjdXRpdmUgUGFpcnMgU3BhY2luZ3MgRGlzdHJpYnV0aW9uIENvbXBhcmlzb24iLCB4bGFiID0gIkRpc3RhbmNlIGJldHdlZW4gQ29uc2VjdXRpdmUgUGFpcnMgb2YgUGFsaW5kcm9tZXMgTG9jYXRpb25zIiwgeWxpbSA9IGMoMCwwLjAwMSkpCmxpbmVzKGRlbnNpdHkoZGlzdGFuY2UucGFpcnMsIGFkanVzdCA9IDIpLCBjb2wgPSByZ2IoMSwwLDAsMC41KSkKRXhwbyA8LSByZXhwKG4tMiwgcmF0ZSA9IDEvbWVhbihkaXN0YW5jZS5wYWlycykpCmhpc3QoRXhwbywgYnJlYWtzID0gMTUsIGNvbCA9IHJnYigwLDAsMSwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIGFkZCA9IFRSVUUpCmxpbmVzKGRlbnNpdHkoRXhwbywgYWRqdXN0ID0gMiksIGNvbCA9IHJnYigwLDAsMSwwLjUpKQpsZWdlbmQoeCA9IDQyMDAsIHkgPSAwLjAwMDUsIGxlZ2VuZCA9IGMoIlNhbXBsZSIsICJFeHBvbmVudGlhbCIpLCBsdHkgPSBjKDEsMSksIGNvbCA9IGMocmdiKDEsMCwwLDAuNSksIHJnYigwLDAsMSwwLjUpKSkKCiMgQ2hpLXNxdWFyZSBHb29kbmVzcyBvZiBGaXQgVGVzdAojIENhc2UgMTogRGl2aWRlZCBpbiA3IGludGVydmFscwojIENvbnN0cnVjdCBleHBlY3RlZCBudW1iZXIgb2YgaW50ZXJ2YWxzCnNwYWNpbmdzLm9ic2VydmVkIDwtIHNvcnQoZGlzdGFuY2UucGFpcnMsIGRlY3JlYXNpbmcgPSBGQUxTRSkKbGFtYmRhIDwtIDEvbWVhbihkaXN0YW5jZS5wYWlycykKc3BhY2luZ3MuaW50ZXJ2YWxzIDwtIGFzLm51bWVyaWMocXVhbnRpbGUoc3BhY2luZ3Mub2JzZXJ2ZWQsIHByb2JzID0gYygwLDAuMDUsIDAuMSwgMC4zLCAwLjUsIDAuNywgMC45LDEpKSkKc3BhY2luZ3MuZXhwZWN0ZWQgPC0gKG4tMikqKGV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stbGVuZ3RoKHNwYWNpbmdzLmludGVydmFscyldKS1leHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLTFdKSkKc3BhY2luZ3MuZXhwZWN0ZWRbbGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKV0gPC0gbi1zdW0oc3BhY2luZ3MuZXhwZWN0ZWRbMTpsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpLTFdKQpzcGFjaW5ncy5vYnNlcnZlZCA8LSBhcy5udW1lcmljKHRhYmxlKGN1dChkaXN0YW5jZS5wYWlycywgYnJlYWtzID0gc3BhY2luZ3MuaW50ZXJ2YWxzLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpKSkKCmNvbnRpbmdlbmN5XzcgPC0gZGF0YS5mcmFtZShzcGFjaW5ncy5pbnRlcnZhbHNbLTFdLHNwYWNpbmdzLm9ic2VydmVkLHNwYWNpbmdzLmV4cGVjdGVkKQpjb250aW5nZW5jeV83CgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj01KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9NSwgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIHdoZW4gdGhlIGRpc3RhbmNlIGlzIHNwbGl0ZWQgaW50byA3IHN1Yi1pbnRlcnZhbHMgaXMnLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKSAvIHNxcnQoc3BhY2luZ3MuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlPSdoJywgeWxhYj0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHhsYWI9J1NwYWNpbmdzIGJldHdlZW4gUGFsaW5kcm9tZSBQYWlycycsIG1haW49J1Bsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gNyBiaW5zKScpCgojIENhc2UgMjogRGl2aWRlZCBpbiAxMCBpbnRlcnZhbHMKIyBDb25zdHJ1Y3QgZXhwZWN0ZWQgbnVtYmVyIG9mIGludGVydmFscwpzcGFjaW5ncy5vYnNlcnZlZCA8LSBzb3J0KGRpc3RhbmNlLnBhaXJzLCBkZWNyZWFzaW5nID0gRkFMU0UpCnNwYWNpbmdzLmludGVydmFscyA8LSBhcy5udW1lcmljKHF1YW50aWxlKHNwYWNpbmdzLm9ic2VydmVkLCBwcm9icyA9IGMoc2VxKDAsMSwgYnkgPSAwLjEpKSkpCnNwYWNpbmdzLmV4cGVjdGVkIDwtIChuLTIpKihleHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLWxlbmd0aChzcGFjaW5ncy5pbnRlcnZhbHMpXSktZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSkpCnNwYWNpbmdzLmV4cGVjdGVkW2xlbmd0aChzcGFjaW5ncy5leHBlY3RlZCldIDwtIG4tc3VtKHNwYWNpbmdzLmV4cGVjdGVkWzE6bGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKS0xXSkKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyh0YWJsZShjdXQoZGlzdGFuY2UucGFpcnMsIGJyZWFrcyA9IHNwYWNpbmdzLmludGVydmFscywgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkpCgpjb250aW5nZW5jeV8xMCA8LSBkYXRhLmZyYW1lKHNwYWNpbmdzLmludGVydmFsc1stMV0sc3BhY2luZ3Mub2JzZXJ2ZWQsc3BhY2luZ3MuZXhwZWN0ZWQpCmNvbnRpbmdlbmN5XzEwCgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj04KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9OCwgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIHdoZW4gdGhlIGRpc3RhbmNlIGlzIHNwbGl0ZWQgaW50byAxMCBzdWItaW50ZXJ2YWxzIGlzJywgcF92YWx1ZSkpCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCkgLyBzcXJ0KHNwYWNpbmdzLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZT0naCcsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLCB4bGFiPSdTcGFjaW5ncyBiZXR3ZWVuIFBhbGluZHJvbWUgUGFpcnMnLCBtYWluPSdQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgTG9jYXRpb25zIChkaXZpZGVkIGluIDEwIGJpbnMpJykKCiMgQ2FzZSAzOiBEaXZpZGVkIGluIDIwIGludGVydmFscwojIENvbnN0cnVjdCBleHBlY3RlZCBudW1iZXIgb2YgaW50ZXJ2YWxzCnNwYWNpbmdzLm9ic2VydmVkIDwtIHNvcnQoZGlzdGFuY2UucGFpcnMsIGRlY3JlYXNpbmcgPSBGQUxTRSkKc3BhY2luZ3MuaW50ZXJ2YWxzIDwtIGFzLm51bWVyaWMocXVhbnRpbGUoc3BhY2luZ3Mub2JzZXJ2ZWQsIHByb2JzID0gYyhzZXEoMCwxLCBieSA9IDAuMDUpKSkpCnNwYWNpbmdzLmV4cGVjdGVkIDwtIChuLTIpKihleHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLWxlbmd0aChzcGFjaW5ncy5pbnRlcnZhbHMpXSktZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSkpCnNwYWNpbmdzLmV4cGVjdGVkW2xlbmd0aChzcGFjaW5ncy5leHBlY3RlZCldIDwtIG4tc3VtKHNwYWNpbmdzLmV4cGVjdGVkWzE6bGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKS0xXSkKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyh0YWJsZShjdXQoZGlzdGFuY2UucGFpcnMsIGJyZWFrcyA9IHNwYWNpbmdzLmludGVydmFscywgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkpCgpjb250aW5nZW5jeV8yMCA8LSBkYXRhLmZyYW1lKHNwYWNpbmdzLmludGVydmFsc1stMV0sc3BhY2luZ3Mub2JzZXJ2ZWQsc3BhY2luZ3MuZXhwZWN0ZWQpCmNvbnRpbmdlbmN5XzIwCgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj0xOCkKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmPTE4LCBsb3dlci50YWlsPUZBTFNFKQpwcmludChwYXN0ZSgnVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDIwIHN1Yi1pbnRlcnZhbHMgaXMnLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKSAvIHNxcnQoc3BhY2luZ3MuZXhwZWN0ZWQpCgpwbG90KFJlc2lkdWFscywgdHlwZSA9ICdoJywgeWxhYiA9ICJTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIiwgeGxhYiA9ICJTcGFjaW5ncyBiZXR3ZWVuIFBhbGluZHJvbWUgUGFpcnMiLCBtYWluID0gIlBsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gMjAgYmlucykiKQoKIyBDb25zZWN1dGl2ZSBUcmlwbGV0cwpsb2NhdGlvbnMuc29ydGVkIDwtICBzb3J0KGxvY2F0aW9ucywgZGVjcmVhc2luZyA9IEZBTFNFKQpsb2NhdGlvbnMudHJpcGxldHMgPC0gbG9jYXRpb25zLnNvcnRlZFstbGVuZ3RoKGxvY2F0aW9ucy5zb3J0ZWQpXQpsb2NhdGlvbnMudHJpcGxldHMgPC0gbG9jYXRpb25zLnRyaXBsZXRzWy1sZW5ndGgobG9jYXRpb25zLnRyaXBsZXRzKV0KZGlzdGFuY2UudHJpcGxldHMgPC0gYWJzKGxvY2F0aW9ucy5zb3J0ZWRbLTFdWy0xXVstMV0tbG9jYXRpb25zLnRyaXBsZXRzWy1sZW5ndGgobG9jYXRpb25zLnRyaXBsZXRzKV0pCgojIEhpc3RvZ3JhbSBvZiBzcGFjaW5ncyBvZiBwYWxpbmRyb21lcyBpbiBvcmlnaW5hbCBkYXRhIGFuZCBleHBvbmVudGlhbCBkaXN0cmlidXRpb24KaGlzdChkaXN0YW5jZS50cmlwbGV0cywgYnJlYWtzPSAxNSwgY29sID0gcmdiKDEsMCwwLDAuNSksIHByb2JhYmlsaXR5ID0gVFJVRSwgbWFpbiA9ICJDb25zZWN1dGl2ZSBUcmlwbGV0cyBTcGFjaW5ncyBEaXN0cmlidXRpb24gQ29tcGFyaXNvbiIsIHhsYWIgPSAiRGlzdGFuY2UgYmV0d2VlbiBDb25zZWN1dGl2ZSBQYWxpbmRyb21lcyBUcmlwbGV0cyIsIHlsaW0gPSBjKDAsMC4wMDA0KSkKbGluZXMoZGVuc2l0eShkaXN0YW5jZS50cmlwbGV0cywgYWRqdXN0ID0gMiksIGNvbCA9IHJnYigxLDAsMCwwLjUpKQpHYW0gPC0gcmdhbW1hKG4tMiwgMiwgcmF0ZSA9IDEvbWVhbihkaXN0YW5jZS5wYWlycykpCmhpc3QoR2FtLCBicmVha3MgPSAxNSwgY29sID0gcmdiKDAsMCwxLDAuNSksIHByb2JhYmlsaXR5ID0gVFJVRSwgYWRkID0gVFJVRSkKbGluZXMoZGVuc2l0eShHYW0sIGFkanVzdCA9IDIpLCBjb2wgPSByZ2IoMCwwLDEsMC41KSkKbGVnZW5kKHggPSA1MDAwLCB5ID0gMC4wMDAzLCBsZWdlbmQgPSBjKCJTYW1wbGUiLCAiR2FtbWEiKSwgbHR5ID0gYygxLDEpLCBjb2wgPSBjKHJnYigxLDAsMCwwLjUpLCByZ2IoMCwwLDEsMC41KSkpCgojIENoaS1zcXVhcmUgR29vZG5lc3Mgb2YgRml0IFRlc3QgKE5lZWQgdG8gYmUgY2hhbmdlZCkKIyBDYXNlIDE6IERpdmlkZWQgaW4gNyBpbnRlcnZhbHMKIyBDb25zdHJ1Y3QgZXhwZWN0ZWQgbnVtYmVyIG9mIGludGVydmFscwpzcGFjaW5ncy5vYnNlcnZlZCA8LSBzb3J0KGRpc3RhbmNlLnRyaXBsZXRzLCBkZWNyZWFzaW5nID0gRkFMU0UpCmxhbWJkYSA8LSAyL21lYW4oZGlzdGFuY2UucGFpcnMpCnNwYWNpbmdzLmludGVydmFscyA8LSBhcy5udW1lcmljKHF1YW50aWxlKHNwYWNpbmdzLm9ic2VydmVkLCBwcm9icyA9IGMoMCwwLjA1LCAwLjEsIDAuMywgMC41LCAwLjcsIDAuOSwxKSkpCnNwYWNpbmdzLmV4cGVjdGVkIDwtIChuLTMpKihleHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLWxlbmd0aChzcGFjaW5ncy5pbnRlcnZhbHMpXSktZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSkpCnNwYWNpbmdzLmV4cGVjdGVkW2xlbmd0aChzcGFjaW5ncy5leHBlY3RlZCldIDwtIG4tc3VtKHNwYWNpbmdzLmV4cGVjdGVkWzE6bGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKS0xXSkKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyh0YWJsZShjdXQoZGlzdGFuY2UucGFpcnMsIGJyZWFrcyA9IHNwYWNpbmdzLmludGVydmFscywgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkpCmNvbnRpbmdlbmN5XzcgPC0gZGF0YS5mcmFtZShzcGFjaW5ncy5pbnRlcnZhbHNbLTFdLHNwYWNpbmdzLm9ic2VydmVkLHNwYWNpbmdzLmV4cGVjdGVkKQpjb250aW5nZW5jeV83CgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocCA9IDAuOTUsIGRmID0gNSkKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmID0gNSwgbG93ZXIudGFpbCA9IEZBTFNFKQpwcmludChwYXN0ZSgiVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDcgc3ViLWludGVydmFscyBpcyIsIHBfdmFsdWUpKQojIyBWaXN1YWxpemF0aW9uIG9mIHRoZSBSZXNpZHVhbApSZXNpZHVhbHMgPC0gKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpIC8gc3FydChzcGFjaW5ncy5leHBlY3RlZCkKcGxvdChSZXNpZHVhbHMsIHR5cGUgPSAnaCcsIHlsYWIgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIsIHhsYWIgPSAiUGFsaW5kcm9tZSBsb2NhdGlvbnMiLCBtYWluID0gIlBsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gNyBiaW5zKSIpCgojIENhc2UgMjogRGl2aWRlZCBpbiAxMCBpbnRlcnZhbHMKIyBDb25zdHJ1Y3QgZXhwZWN0ZWQgbnVtYmVyIG9mIGludGVydmFscwpzcGFjaW5ncy5vYnNlcnZlZCA8LSBzb3J0KGRpc3RhbmNlLnBhaXJzLCBkZWNyZWFzaW5nID0gRkFMU0UpCnNwYWNpbmdzLmludGVydmFscyA8LSBhcy5udW1lcmljKHF1YW50aWxlKHNwYWNpbmdzLm9ic2VydmVkLCBwcm9icyA9IGMoc2VxKDAsMSwgYnkgPSAwLjEpKSkpCnNwYWNpbmdzLmV4cGVjdGVkIDwtIChuLTMpKihleHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLWxlbmd0aChzcGFjaW5ncy5pbnRlcnZhbHMpXSktZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSkpCnNwYWNpbmdzLmV4cGVjdGVkW2xlbmd0aChzcGFjaW5ncy5leHBlY3RlZCldIDwtIG4tc3VtKHNwYWNpbmdzLmV4cGVjdGVkWzE6bGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKS0xXSkKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyh0YWJsZShjdXQoZGlzdGFuY2UucGFpcnMsIGJyZWFrcyA9IHNwYWNpbmdzLmludGVydmFscywgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkpCmNvbnRpbmdlbmN5XzEwIDwtIGRhdGEuZnJhbWUoc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSxzcGFjaW5ncy5vYnNlcnZlZCxzcGFjaW5ncy5leHBlY3RlZCkKY29udGluZ2VuY3lfMTAKCmNoaV8yIDwtIHN1bSgoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCleMi9zcGFjaW5ncy5leHBlY3RlZCkKY2hpMl9jb21wYXJlIDwtIHFjaGlzcShwID0gMC45NSwgZGYgPSA4KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGYgPSA4LCBsb3dlci50YWlsID0gRkFMU0UpCnByaW50KHBhc3RlKCJUaGUgcF92YWx1ZSB3aGVuIHRoZSBkaXN0YW5jZSBpcyBzcGxpdGVkIGludG8gMTAgc3ViLWludGVydmFscyBpcyIsIHBfdmFsdWUpKQojIyBWaXN1YWxpemF0aW9uIG9mIHRoZSBSZXNpZHVhbApSZXNpZHVhbHMgPC0gKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpIC8gc3FydChzcGFjaW5ncy5leHBlY3RlZCkKcGxvdChSZXNpZHVhbHMsIHR5cGUgPSAnaCcsIHlsYWIgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIsIHhsYWIgPSAiUGFsaW5kcm9tZSBsb2NhdGlvbnMiLCBtYWluID0gIlBsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gMTAgYmlucykiKQoKIyBDYXNlIDM6IERpdmlkZWQgaW4gMjAgaW50ZXJ2YWxzCiMgQ29uc3RydWN0IGV4cGVjdGVkIG51bWJlciBvZiBpbnRlcnZhbHMKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gc29ydChkaXN0YW5jZS5wYWlycywgZGVjcmVhc2luZyA9IEZBTFNFKQpzcGFjaW5ncy5pbnRlcnZhbHMgPC0gYXMubnVtZXJpYyhxdWFudGlsZShzcGFjaW5ncy5vYnNlcnZlZCwgcHJvYnMgPSBjKHNlcSgwLDEsIGJ5ID0gMC4wNSkpKSkKc3BhY2luZ3MuZXhwZWN0ZWQgPC0gKG4tMykqKGV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stbGVuZ3RoKHNwYWNpbmdzLmludGVydmFscyldKS1leHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLTFdKSkKc3BhY2luZ3MuZXhwZWN0ZWRbbGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKV0gPC0gbi1zdW0oc3BhY2luZ3MuZXhwZWN0ZWRbMTpsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpLTFdKQpzcGFjaW5ncy5vYnNlcnZlZCA8LSBhcy5udW1lcmljKHRhYmxlKGN1dChkaXN0YW5jZS5wYWlycywgYnJlYWtzID0gc3BhY2luZ3MuaW50ZXJ2YWxzLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpKSkKY29udGluZ2VuY3lfMjAgPC0gZGF0YS5mcmFtZShzcGFjaW5ncy5pbnRlcnZhbHNbLTFdLHNwYWNpbmdzLm9ic2VydmVkLHNwYWNpbmdzLmV4cGVjdGVkKQpjb250aW5nZW5jeV8yMAoKY2hpXzIgPC0gc3VtKChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKV4yL3NwYWNpbmdzLmV4cGVjdGVkKQpjaGkyX2NvbXBhcmUgPC0gcWNoaXNxKHAgPSAwLjk1LCBkZiA9IDE4KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGYgPSAxOCwgbG93ZXIudGFpbCA9IEZBTFNFKQpwcmludChwYXN0ZSgiVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDIwIHN1Yi1pbnRlcnZhbHMgaXMiLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKSAvIHNxcnQoc3BhY2luZ3MuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlID0gJ2gnLCB5bGFiID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiLCB4bGFiID0gIlBhbGluZHJvbWUgbG9jYXRpb25zIiwgbWFpbiA9ICJQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgTG9jYXRpb25zIChkaXZpZGVkIGluIDIwIGJpbnMpIikKYGBgCgoKIyMgU2NlbmFyaW8gMzogQ291bnRzClVzZSBncmFwaGljYWwgbWV0aG9kcyBhbmQgbW9yZSBmb3JtYWwgc3RhdGlzdGljYWwgdGVzdHMgdG8gZXhhbWluZSB0aGUgY291bnRzIG9mIHBhbGluZHJvbWVzIGluIHZhcmlvdXMgcmVnaW9ucyBvZiB0aGUgRE5BLiBTcGxpdCB0aGUgRE5BIGludG8gbm9ub3ZlcmxhcHBpbmcgcmVnaW9ucyBvZiBlcXVhbCBsZW5ndGggdG8gY29tcGFyZSB0aGUgbnVtYmVyIG9mIHBhbGluZG9tcmVzIGluIGFuIGludGVydmFsIHRvIHRoZSBudW1iZXIgb2YgdGhhdCB5b3Ugd291bGQgZXhwZWN0IGZyb20gdW5pZm9ybSByYW5kb20gc2NhdHRlci4gVGhlIGNvdW50cyBmb3Igc2hvcnRlciByZWdpb25zIHdpbGwgYmUgbW9yZSB2YXJpYWJsZSB0aGFuIHRob3NlIGZvciBsb2duZXIgcmVnaW9ucy4gQWxzbywgY29uc2lkZXIgY2xhc3NpZnlpbmcgdGhlIHJlZ2lvbnMgYWNjb3JkaW5nIHRvIHRoZSBudW1iZXIgb2YgY291bnRzLgoKYGBge3J9CnJlZ2lvbnNwbGl0IDwtIGZ1bmN0aW9uKG4ucmVnaW9uLCBnZW5lLCBzaXRlKXsKICBjb3VudC5pbnQgPC0gdGFibGUoY3V0KHNpdGUsIGJyZWFrcyA9IHNlcSgxLCBsZW5ndGgoZ2VuZSksIGxlbmd0aC5vdXQ9bi5yZWdpb24rMSksIGluY2x1ZGUubG93ZXN0PVRSVUUpKQogIGNvdW50LnZlY3RvciA8LSBhcy52ZWN0b3IoY291bnQuaW50KQogIGNvdW50LnRhYiA8LSB0YWJsZShjb3VudC52ZWN0b3IpCiAgcmV0dXJuIChjb3VudC50YWIpCn0KYGBgCgpgYGB7cn0KIyBDYXNlIDE6IGRpdmlkZWQgYnkgNDAgaW50ZXJ2YWxzCm4ucmVnaW9uIDwtIDQwCmdlbmUgPC0gc2VxKDEsTikKb2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyhyZWdpb25zcGxpdChuLnJlZ2lvbiwgZ2VuZSwgbG9jYXRpb25zKSkKaW50ZXJ2YWwgPC0gYXMubnVtZXJpYyhuYW1lcyhyZWdpb25zcGxpdChuLnJlZ2lvbiwgZ2VuZSwgbG9jYXRpb25zKSkpCmxhbWJkYSA8LSBuL24ucmVnaW9uCgojIEhpc3RvZ3JhbSBvZiBjb3VudHMgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgcG9pc3NvbiBkaXN0cmlidXRpb24KY291bnRzLmhpc3QgPC0gcmVnaW9uc3BsaXQobi5yZWdpb24sIGdlbmUsIGxvY2F0aW9ucykKaGlzdChjb3VudHMuaGlzdCwgYnJlYWtzPSAxNSwgY29sID0gcmdiKDEsMCwwLDAuNSksIHByb2JhYmlsaXR5ID0gVFJVRSwgbWFpbiA9ICJDb3VudHMgb2YgUGFsaW5kcm9tZSBEaXN0cmlidXRpb24gQ29tcGFyaXNvbiAoNDAgc3ViLWludGVydmFscykiLCB4bGFiID0gIkNvdW50cyBmb3VuZCBwZXIgaW50ZXJ2YWwiLCB5bGltID0gYygwLDAuNikpCmxpbmVzKGRlbnNpdHkoY291bnRzLmhpc3QsIGFkanVzdCA9IDIpLCBjb2wgPSByZ2IoMSwwLDAsMC41KSkKUG9pcyA8LSBycG9pcyhuLCBsYW1iZGEpCmhpc3QoUG9pcywgYnJlYWtzID0gMTUsIGNvbCA9IHJnYigwLDAsMSwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIGFkZCA9IFRSVUUpCmxpbmVzKGRlbnNpdHkoUG9pcywgYWRqdXN0ID0gMiksIGNvbCA9IHJnYigwLDAsMSwwLjUpKQpsZWdlbmQoeCA9IDcsIHkgPSAwLjUsIGxlZ2VuZCA9IGMoIlNhbXBsZSIsICJQb2lzc29uIiksIGx0eSA9IGMoMSwxKSwgY29sID0gYyhyZ2IoMSwwLDAsMC41KSwgcmdiKDAsMCwxLDAuNSkpKQoKIyBDaGktc3FyIEdvb2RuZXNzIG9mIEZpdCB0ZXN0CmV4cGVjdGVkIDwtIG4ucmVnaW9uKmV4cCgtbGFtYmRhKSogbGFtYmRhKiooaW50ZXJ2YWwpL2ZhY3RvcmlhbChpbnRlcnZhbCkKZm9yIChpIGluIGMoMDoyKSl7CiAgZXhwZWN0IDwtIG4ucmVnaW9uKmV4cCgtbGFtYmRhKSogbGFtYmRhKiooaSkvZmFjdG9yaWFsKGkpCiAgZXhwZWN0ZWRbMV0gPC0gZXhwZWN0ZWRbMV0rIGV4cGVjdAp9CmV4cGVjdCA8LSBuLnJlZ2lvbipleHAoLWxhbWJkYSkqIGxhbWJkYSoqKDExKS9mYWN0b3JpYWwoMTEpCmV4cGVjdGVkWzhdIDwtIGV4cGVjdGVkWzhdKyBleHBlY3QKZXhwZWN0ZWRbMTBdIDwtIDAKZm9yIChpIGluIGMoMToxMikpewogIGV4cGVjdCA8LSBleHAoLWxhbWJkYSkqIGxhbWJkYSoqKGkpL2ZhY3RvcmlhbChpKQogIGV4cGVjdGVkWzEwXSA8LSBleHBlY3RlZFsxMF0rIGV4cGVjdAp9CmV4cGVjdGVkWzEwXSA8LSAoMS1leHBlY3RlZFsxMF0pKm4ucmVnaW9uCmNvdW50cy5leHBlY3RlZCA8LSBjKCkKY291bnRzLmludGVydmFsIDwtIGMoKQpjb3VudHMub2JzZXJ2ZWQgPC0gYygpCiMgR3JvdXAgYmlucwpjb3VudHMuZXhwZWN0ZWRbMV0gPC0gc3VtKGV4cGVjdGVkWzE6Ml0pCmNvdW50cy5leHBlY3RlZFsyXSA8LSBzdW0oZXhwZWN0ZWRbMzo0XSkKY291bnRzLmV4cGVjdGVkWzNdIDwtIHN1bShleHBlY3RlZFs1XSkKY291bnRzLmV4cGVjdGVkWzRdIDwtIHN1bShleHBlY3RlZFs2OjddKQpjb3VudHMuZXhwZWN0ZWRbNV0gPC0gc3VtKGV4cGVjdGVkWzg6MTBdKQpjb3VudHMub2JzZXJ2ZWRbMV0gPC0gc3VtKG9ic2VydmVkWzE6Ml0pCmNvdW50cy5vYnNlcnZlZFsyXSA8LSBzdW0ob2JzZXJ2ZWRbMzo0XSkKY291bnRzLm9ic2VydmVkWzNdIDwtIHN1bShvYnNlcnZlZFs1XSkKY291bnRzLm9ic2VydmVkWzRdIDwtIHN1bShvYnNlcnZlZFs2OjddKQpjb3VudHMub2JzZXJ2ZWRbNV0gPC0gc3VtKG9ic2VydmVkWzg6MTBdKQpjb3VudHMuaW50ZXJ2YWxbMV0gPC0gaW50ZXJ2YWxbMl0KY291bnRzLmludGVydmFsWzJdIDwtIGludGVydmFsWzRdCmNvdW50cy5pbnRlcnZhbFszXSA8LSBpbnRlcnZhbFs1XQpjb3VudHMuaW50ZXJ2YWxbNF0gPC0gaW50ZXJ2YWxbN10KY291bnRzLmludGVydmFsWzVdIDwtIGludGVydmFsWzddKzEKY291bnRzLnRhYmxlNDAgPC0gZGF0YS5mcmFtZShjb3VudHMuaW50ZXJ2YWwsY291bnRzLm9ic2VydmVkLGNvdW50cy5leHBlY3RlZCkKY291bnRzLnRhYmxlNDAKIyBDaGktc3F1YXJlIHN0YXRpc3RpYwpjaGlfMiA8LSBzdW0oKGNvdW50cy5vYnNlcnZlZCAtIGNvdW50cy5leHBlY3RlZCleMi9jb3VudHMuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocCA9IDAuOTUsIGRmID0gMykKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmID0gMywgbG93ZXIudGFpbCA9IEZBTFNFKQpwcmludChwYXN0ZSgiVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDQwIHN1Yi1pbnRlcnZhbHMgaXMiLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChjb3VudHMub2JzZXJ2ZWQgLSBjb3VudHMuZXhwZWN0ZWQpIC8gc3FydChjb3VudHMuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlID0gJ2gnLCB5bGFiID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiLCB4bGFiID0gIlBhbGluZHJvbWUgY291bnRzIiwgbWFpbiA9ICJQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgQ291bnRzIChkaXZpZGVkIGluIDQwIHN1Yi1pbnRlcnZhbHMpIikKCmBgYApgYGB7cn0KIyBDYXNlIDI6IGRpdmlkZWQgYnkgNjAgaW50ZXJ2YWxzCm4ucmVnaW9uIDwtIDYwCmdlbmUgPC0gc2VxKDEsTikKCm9ic2VydmVkIDwtIGFzLm51bWVyaWMocmVnaW9uc3BsaXQobi5yZWdpb24sIGdlbmUsIGxvY2F0aW9ucykpCmludGVydmFsIDwtIGFzLm51bWVyaWMobmFtZXMocmVnaW9uc3BsaXQobi5yZWdpb24sIGdlbmUsIGxvY2F0aW9ucykpKQpsYW1iZGEgPC0gbi9uLnJlZ2lvbgoKIyBIaXN0b2dyYW0gb2YgY291bnRzIG9mIHBhbGluZHJvbWVzIGluIG9yaWdpbmFsIGRhdGEgYW5kIHBvaXNzb24gZGlzdHJpYnV0aW9uCmNvdW50cy5oaXN0IDwtIHJlZ2lvbnNwbGl0KG4ucmVnaW9uLCBnZW5lLCBsb2NhdGlvbnMpCmhpc3QoY291bnRzLmhpc3QsIGJyZWFrcz0gMTUsIGNvbCA9IHJnYigxLDAsMCwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAiQ291bnRzIG9mIFBhbGluZHJvbWUgRGlzdHJpYnV0aW9uIENvbXBhcmlzb24gKDYwIHN1Yi1pbnRlcnZhbHMpIiwgeGxhYiA9ICJDb3VudHMgZm91bmQgcGVyIGludGVydmFsIiwgeWxpbSA9IGMoMCwwLjYpKQpsaW5lcyhkZW5zaXR5KGNvdW50cy5oaXN0LCBhZGp1c3QgPSAyKSwgY29sID0gcmdiKDEsMCwwLDAuNSkpClBvaXMgPC0gcnBvaXMobiwgbGFtYmRhKQpoaXN0KFBvaXMsIGJyZWFrcyA9IDE1LCBjb2wgPSByZ2IoMCwwLDEsMC41KSwgcHJvYmFiaWxpdHkgPSBUUlVFLCBhZGQgPSBUUlVFKQpsaW5lcyhkZW5zaXR5KFBvaXMsIGFkanVzdCA9IDIpLCBjb2wgPSByZ2IoMCwwLDEsMC41KSkKbGVnZW5kKHggPSA3LCB5ID0gMC41LCBsZWdlbmQgPSBjKCJTYW1wbGUiLCAiUG9pc3NvbiIpLCBsdHkgPSBjKDEsMSksIGNvbCA9IGMocmdiKDEsMCwwLDAuNSksIHJnYigwLDAsMSwwLjUpKSkKCiMgQ2hpLXNxciBHb29kbmVzcyBvZiBGaXQgdGVzdApleHBlY3RlZCA8LSBuLnJlZ2lvbipleHAoLWxhbWJkYSkqIGxhbWJkYSoqKGludGVydmFsKS9mYWN0b3JpYWwoaW50ZXJ2YWwpCmV4cGVjdCA8LSBuLnJlZ2lvbipleHAoLWxhbWJkYSkqIGxhbWJkYSoqKDApL2ZhY3RvcmlhbCgwKQpleHBlY3RlZFsxXSA8LSBleHBlY3RlZFsxXSsgZXhwZWN0CmZvciAoaSBpbiBjKDEwOjExKSl7CiAgZXhwZWN0IDwtIG4ucmVnaW9uKmV4cCgtbGFtYmRhKSogbGFtYmRhKiooaSkvZmFjdG9yaWFsKGkpCiAgZXhwZWN0ZWRbOV0gPC0gZXhwZWN0ZWRbOV0rIGV4cGVjdAp9CmV4cGVjdGVkWzExXSA8LSAwCmZvciAoaSBpbiBjKDE6MTIpKXsKICBleHBlY3QgPC0gZXhwKC1sYW1iZGEpKiBsYW1iZGEqKihpKS9mYWN0b3JpYWwoaSkKICBleHBlY3RlZFsxMV0gPC0gZXhwZWN0ZWRbMTFdKyBleHBlY3QKfQpleHBlY3RlZFsxMV0gPC0gKDEtZXhwZWN0ZWRbMTFdKSpuLnJlZ2lvbgpjb3VudHMuZXhwZWN0ZWQgPC0gYygpCmNvdW50cy5pbnRlcnZhbCA8LSBjKCkKY291bnRzLm9ic2VydmVkIDwtIGMoKQoKIyBHcm91cCBiaW5zCmNvdW50cy5leHBlY3RlZFsxXSA8LSBzdW0oZXhwZWN0ZWRbMToyXSkKY291bnRzLmV4cGVjdGVkWzI6Nl0gPC0gZXhwZWN0ZWRbMzo3XQpjb3VudHMuZXhwZWN0ZWRbN10gPC0gc3VtKGV4cGVjdGVkWzg6MTFdKQpjb3VudHMub2JzZXJ2ZWRbMV0gPC0gc3VtKG9ic2VydmVkWzE6Ml0pCmNvdW50cy5vYnNlcnZlZFsyOjZdIDwtIG9ic2VydmVkWzM6N10KY291bnRzLm9ic2VydmVkWzddIDwtIHN1bShvYnNlcnZlZFs4OjExXSkKY291bnRzLmludGVydmFsWzFdIDwtIGludGVydmFsWzJdCmNvdW50cy5pbnRlcnZhbFsyOjZdIDwtIGludGVydmFsWzM6N10KY291bnRzLmludGVydmFsWzddIDwtIGludGVydmFsWzddKzEKY291bnRzLnRhYmxlNjAgPC0gZGF0YS5mcmFtZShjb3VudHMuaW50ZXJ2YWwsY291bnRzLm9ic2VydmVkLGNvdW50cy5leHBlY3RlZCkKY291bnRzLnRhYmxlNjAKIyBDaGktc3F1YXJlIHN0YXRpc3RpYwpjaGlfMiA8LSBzdW0oKGNvdW50cy5vYnNlcnZlZCAtIGNvdW50cy5leHBlY3RlZCleMi9jb3VudHMuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocCA9IDAuOTUsIGRmID0gNSkKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmID0gNSwgbG93ZXIudGFpbCA9IEZBTFNFKQpwcmludChwYXN0ZSgiVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDYwIHN1Yi1pbnRlcnZhbHMgaXMiLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChjb3VudHMub2JzZXJ2ZWQgLSBjb3VudHMuZXhwZWN0ZWQpIC8gc3FydChjb3VudHMuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlID0gJ2gnLCB5bGFiID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiLCB4bGFiID0gIlBhbGluZHJvbWUgY291bnRzIiwgbWFpbiA9ICJQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgQ291bnRzIChkaXZpZGVkIGluIDYwIHN1Yi1pbnRlcnZhbHMpIikKYGBgCgpgYGB7cn0KIyBDYXNlIDM6IGRpdmlkZWQgYnkgODAgaW50ZXJ2YWxzCm4ucmVnaW9uIDwtIDgwCmdlbmUgPC0gc2VxKDEsTikKCm9ic2VydmVkIDwtIGFzLm51bWVyaWMocmVnaW9uc3BsaXQobi5yZWdpb24sIGdlbmUsIGxvY2F0aW9ucykpCmludGVydmFsIDwtIGFzLm51bWVyaWMobmFtZXMocmVnaW9uc3BsaXQobi5yZWdpb24sIGdlbmUsIGxvY2F0aW9ucykpKQpsYW1iZGEgPC0gbi9uLnJlZ2lvbgoKIyBIaXN0b2dyYW0gb2YgY291bnRzIG9mIHBhbGluZHJvbWVzIGluIG9yaWdpbmFsIGRhdGEgYW5kIHBvaXNzb24gZGlzdHJpYnV0aW9uCmNvdW50cy5oaXN0IDwtIHJlZ2lvbnNwbGl0KG4ucmVnaW9uLCBnZW5lLCBsb2NhdGlvbnMpCmhpc3QoY291bnRzLmhpc3QsIGJyZWFrcz0gMTUsIGNvbCA9IHJnYigxLDAsMCwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAiQ291bnRzIG9mIFBhbGluZHJvbWUgRGlzdHJpYnV0aW9uIENvbXBhcmlzb24gKDgwIHN1Yi1pbnRlcnZhbHMpIiwgeGxhYiA9ICJDb3VudHMgZm91bmQgcGVyIGludGVydmFsIiwgeWxpbSA9IGMoMCwwLjYpKQpsaW5lcyhkZW5zaXR5KGNvdW50cy5oaXN0LCBhZGp1c3QgPSAyKSwgY29sID0gcmdiKDEsMCwwLDAuNSkpClBvaXMgPC0gcnBvaXMobiwgbGFtYmRhKQpoaXN0KFBvaXMsIGJyZWFrcyA9IDE1LCBjb2wgPSByZ2IoMCwwLDEsMC41KSwgcHJvYmFiaWxpdHkgPSBUUlVFLCBhZGQgPSBUUlVFKQpsaW5lcyhkZW5zaXR5KFBvaXMsIGFkanVzdCA9IDIpLCBjb2wgPSByZ2IoMCwwLDEsMC41KSkKbGVnZW5kKHggPSA3LCB5ID0gMC41LCBsZWdlbmQgPSBjKCJTYW1wbGUiLCAiUG9pc3NvbiIpLCBsdHkgPSBjKDEsMSksIGNvbCA9IGMocmdiKDEsMCwwLDAuNSksIHJnYigwLDAsMSwwLjUpKSkKCiMgQ2hpLXNxciBHb29kbmVzcyBvZiBGaXQgdGVzdApleHBlY3RlZCA8LSBuLnJlZ2lvbipleHAoLWxhbWJkYSkqIGxhbWJkYSoqKGludGVydmFsKS9mYWN0b3JpYWwoaW50ZXJ2YWwpCmZvciAoaSBpbiBjKDg6OSkpewogIGV4cGVjdCA8LSBuLnJlZ2lvbipleHAoLWxhbWJkYSkqIGxhbWJkYSoqKGkpL2ZhY3RvcmlhbChpKQogIGV4cGVjdGVkWzldIDwtIGV4cGVjdGVkWzldKyBleHBlY3QKfQpleHBlY3RlZFsxMF0gPC0gMApmb3IgKGkgaW4gYygxOjEwKSl7CiAgZXhwZWN0IDwtIGV4cCgtbGFtYmRhKSogbGFtYmRhKiooaSkvZmFjdG9yaWFsKGkpCiAgZXhwZWN0ZWRbMTBdIDwtIGV4cGVjdGVkWzEwXSsgZXhwZWN0Cn0KZXhwZWN0ZWRbMTBdIDwtICgxLWV4cGVjdGVkWzEwXSkqbi5yZWdpb24KY291bnRzLmV4cGVjdGVkIDwtIGMoKQpjb3VudHMuaW50ZXJ2YWwgPC0gYygpCmNvdW50cy5vYnNlcnZlZCA8LSBjKCkKIyBHcm91cCBiaW5zCmNvdW50cy5leHBlY3RlZFsxXSA8LSBzdW0oZXhwZWN0ZWRbMToyXSkKY291bnRzLmV4cGVjdGVkWzI6Nl0gPC0gZXhwZWN0ZWRbMzo3XQpjb3VudHMuZXhwZWN0ZWRbN10gPC0gc3VtKGV4cGVjdGVkWzg6MTBdKQpjb3VudHMub2JzZXJ2ZWRbMV0gPC0gc3VtKG9ic2VydmVkWzE6Ml0pCmNvdW50cy5vYnNlcnZlZFsyOjZdIDwtIG9ic2VydmVkWzM6N10KY291bnRzLm9ic2VydmVkWzddIDwtIHN1bShvYnNlcnZlZFs4OjEwXSkKY291bnRzLmludGVydmFsWzFdIDwtIGludGVydmFsWzJdCmNvdW50cy5pbnRlcnZhbFsyOjZdIDwtIGludGVydmFsWzM6N10KY291bnRzLmludGVydmFsWzddIDwtIGludGVydmFsWzddKzEKY291bnRzLnRhYmxlNjAgPC0gZGF0YS5mcmFtZShjb3VudHMuaW50ZXJ2YWwsY291bnRzLm9ic2VydmVkLGNvdW50cy5leHBlY3RlZCkKY291bnRzLnRhYmxlNjAKIyBDaGktc3F1YXJlIHN0YXRpc3RpYwpjaGlfMiA8LSBzdW0oKGNvdW50cy5vYnNlcnZlZCAtIGNvdW50cy5leHBlY3RlZCleMi9jb3VudHMuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocCA9IDAuOTUsIGRmID0gNSkKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmID0gNSwgbG93ZXIudGFpbCA9IEZBTFNFKQpwcmludChwYXN0ZSgiVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDYwIHN1Yi1pbnRlcnZhbHMgaXMiLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChjb3VudHMub2JzZXJ2ZWQgLSBjb3VudHMuZXhwZWN0ZWQpIC8gc3FydChjb3VudHMuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlID0gJ2gnLCB5bGFiID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiLCB4bGFiID0gIlBhbGluZHJvbWUgY291bnRzIiwgbWFpbiA9ICJQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgQ291bnRzIChkaXZpZGVkIGluIDgwIHN1Yi1pbnRlcnZhbHMpIikKYGBgCgoKIyMgU2NlbmFyaW8gNDogVGhlIEJpZ2dlc3QgQ2x1c3RlcgpEb2VzIHRoZSBpbnRlcnZhbCB3aXRoIHRoZSBncmVhdGVzdCBudW1iZXIgb2YgcGFsaW5kcm9tZXMgaW5kaWNhdGUgYSBwb3RlbnRpYWwgb3JpZ2luIG9mIHJlcGxpY2F0aW9uPyBCZSBjYXJlZnVsIGluIG1ha2luZyB5b3VyIGludGVydmFscywgZm9yIGFueSBzbWFsbCwgYnV0IHNpZ25pZmljYW50IGRldmlhdGlvbnMgZnJvbSByYW5kb20gc2NhdHRlciwgc3VjaCBhcyBhIHRpZ2h0IGNsdXN0ZXIgb2YgYSBmZXcgcGFsaW5kcm9tZXMsIGNvdWxkIGVhc2lseSBnbyB1bmRldGVjdGVkIGlmIHRoZSByZWdpb25zIGV4YW1pbmVkIGFyZSB0b28gbGFyZ2UuIEFsc28sIGlmIHRoZSByZWdpb25zIGFyZSB0b28gc21hbGwsIGEgY2x1c3RlciBvZiBwYWxpbmRyb21lcyBtYXkgYmUgc3BsaXQgYmV0d2VlbiBhZGphY2VudCBpbnRlcmF2bHMgYW5kIG5vdCBhcHBlYXIgYXMgYSBoaWdoLWNvdW50IGludGVydmFsLgpgYGB7cn0KZmluYWwgPC0gYXJyYXkoZGltPWMoNTAwLDEpKQppbnRlcnZhbF9sZW5ndGggPC0gYXJyYXkoZGltPWMoNTAwLDEpKQpsYW1kYSA8LSBhcnJheShkaW09Yyg1MDAsMSkpCmZvciAoayBpbiAyMDoxMDApewogIHRhYiA8LSB0YWJsZShjdXQobG9jYXRpb25zLCBicmVha3M9c2VxKDAsIE4sIGxlbmd0aC5vdXQ9aysxKSwgaW5jbHVkZS5sb3dlc3Q9VFJVRSkpCiAgaGVhZCh0YWIsMTApCiAgdGFiPC1hcy52ZWN0b3IodGFiKQogIGxhbWRhW2ssXSA8LXN1bSh0YWIpL2sKICB0aHJlc2hvbGQgPC1tYXgodGFiKQogIHJlc3VsdCA8LSAwCiAgaW50ZXJ2YWxfbGVuZ3RoW2ssXSA8LSBOL2sKICBmb3IgKGkgaW4gMDoodGhyZXNob2xkLTEpKXsKICAgIHJlc3VsdCA8LSByZXN1bHQrKChsYW1kYVtrXV5pKSpleHAoLWxhbWRhW2tdKS9mYWN0b3JpYWwoaSkpCiAgfQogIGZpbmFsW2ssXSA8LSAxLXJlc3VsdF5rCn0KcmVzdWx0IDwtIGRhdGEuZnJhbWUobGFtZGEsaW50ZXJ2YWxfbGVuZ3RoLGZpbmFsKQoKIyBEaXNwbGF5IFRhYmxlIGNvbnRhaW5pbmcgdGhlIHByb2JhYmlsaXR5IG9mIGEgUG9pc3NvbiBEaXN0cmlidXRpb24gaGF2aW5nIGUgZ3JlYXRlc3QgbnVtYmVyIG9mIGhpdHMgYXQgbGVhc3QgayBmb3IgZWFjaCBzdWItaW50ZXJ2YWwgZGl2aXNpb25zCnJlc3VsdFtjKDQwLDYwLDgwKSxdCmBgYAoKCiMjIEFkZGl0aW9uYWwgU2NlbmFyaW86IEhJViBhbmQgQWdlClRPRE8gRGVzY3JpcHRpb24KYGBge3J9CiMgQ2xlYW4gb3V0ICd1bmtub3duJyBkYXRhIGFuZCBjb252ZXJ0IGZhY3RvciB0byBudW1lcmljYWwgdmFsdWVzCmhlYWx0aCA8LSB0cmFuc2Zvcm0oaGVhbHRoLCBhZ2VfeXJzPWFzLm51bWVyaWMoYWdlX3lycyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaXY9YXMuY2hhcmFjdGVyKGhpdikpCmhlYWx0aC5pbmQgPC0gd2hpY2goaGVhbHRoJGhpdiAhPSAndW5rbm93bicpCmhlYWx0aCA8LSBoZWFsdGhbaGVhbHRoLmluZCxdCgojIFRvdGFsIG51bWJlciBvZiBwZW9wbGUgdGhhdCBoYXZlIGhpdgpwb3B1bGF0aW9uPW5yb3coaGVhbHRoKQpwb3BfaGl2IDwtIG5yb3coaGVhbHRoW3doaWNoKGhlYWx0aCRoaXY9PSdwb3NpdGl2ZScpLF0pCgojIFNwbGl0IHRoZSBhZ2UgaW50byBmb3VyIGdyb3VwcwojIDAtMjAKYWdlX2ZpcnN0IDwtIGhlYWx0aCRhZ2VfeXJzW3doaWNoKGhlYWx0aCRhZ2VfeXJzPDIxKV0KYWdlX3Byb3BvcnRpb25fZmlyc3QgPC0gbGVuZ3RoKGFnZV9maXJzdCkvcG9wdWxhdGlvbgpoaXZfcHJvcG9ydGlvbl9maXJzdDwtIG5yb3coaGVhbHRoW3doaWNoKChoZWFsdGgkaGl2PT0gJ3Bvc2l0aXZlJykgJiAoaGVhbHRoJGFnZV95cnMgPDIxKSksXSkvcG9wX2hpdgoKIyAyMS00MAphZ2Vfc2Vjb25kPC1oZWFsdGgkYWdlX3lyc1t3aGljaChoZWFsdGgkYWdlX3lycz4yMCAmIGhlYWx0aFsnYWdlX3lycyddPDQxKV0KYWdlX3Byb3BvcnRpb25fc2Vjb25kIDwtIGxlbmd0aChhZ2Vfc2Vjb25kKS9wb3B1bGF0aW9uCmhpdl9wcm9wb3J0aW9uX3NlY29uZDwtbnJvdyhoZWFsdGhbd2hpY2goaGVhbHRoJGFnZV95cnM+MjAgJmhlYWx0aCRhZ2VfeXJzPDQxICYgaGVhbHRoJGhpdj09J3Bvc2l0aXZlJyksXSkvcG9wX2hpdgoKIyA0MS02MAphZ2VfdGhpcmQ8LWhlYWx0aCRhZ2VfeXJzW3doaWNoKGhlYWx0aFsnYWdlX3lycyddPjQwICYgaGVhbHRoWydhZ2VfeXJzJ108NjEpXQphZ2VfcHJvcG9ydGlvbl90aGlyZCA8LSBsZW5ndGgoYWdlX3RoaXJkKS9wb3B1bGF0aW9uCmhpdl9wcm9wb3J0aW9uX3RoaXJkPC1ucm93KGhlYWx0aFt3aGljaChoZWFsdGgkYWdlX3lycz40MCAmIGhlYWx0aCRhZ2VfeXJzPDYxICZoZWFsdGgkaGl2PT0ncG9zaXRpdmUnKSxdKS9wb3BfaGl2CgojIDYxKwphZ2VfbGFzdDwtaGVhbHRoJGFnZV95cnNbd2hpY2goaGVhbHRoWydhZ2VfeXJzJ10+NjApXQphZ2VfcHJvcG9ydGlvbl9sYXN0IDwtIGxlbmd0aChhZ2VfbGFzdCkvcG9wdWxhdGlvbgpoaXZfcHJvcG9ydGlvbl9sYXN0PC1ucm93KGhlYWx0aFt3aGljaChoZWFsdGgkYWdlX3lycz42MCAmIGhlYWx0aCRoaXY9PSdwb3NpdGl2ZScpLF0pL3BvcF9oaXYKCiMgRXhwZWN0ZWQgRGF0YQpwb3B1bGF0aW9uX2Rpc3QgPC1jKGFnZV9wcm9wb3J0aW9uX2ZpcnN0LGFnZV9wcm9wb3J0aW9uX3NlY29uZCxhZ2VfcHJvcG9ydGlvbl90aGlyZCxhZ2VfcHJvcG9ydGlvbl9sYXN0KQojIE9ic2VydmVkIERhdGEKaGl2X2Rpc3Q8LWMoaGl2X3Byb3BvcnRpb25fZmlyc3QsaGl2X3Byb3BvcnRpb25fc2Vjb25kLGhpdl9wcm9wb3J0aW9uX3RoaXJkLGhpdl9wcm9wb3J0aW9uX2xhc3QpCmFnZV9kaXN0IDwtIGMoIjAtMjAiLCAiMjEtNDAiLCAiNDEtNjAiLCAiNjErIikKZGF0YS5mcmFtZShhZ2VfZGlzdCxwb3B1bGF0aW9uX2Rpc3QsaGl2X2Rpc3QpCgojIEdvb2RuZXNzLWZpdHRlc3QKY2hpXzIgPC0gc3VtKChoaXZfZGlzdCAtIHBvcHVsYXRpb25fZGlzdCleMi9wb3B1bGF0aW9uX2Rpc3QpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj0zKQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9MywgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIG9mIEdvb2RuZXNzIG9mIEZpdCBUZXN0IGlzJyxwX3ZhbHVlKSkKCiNWaXN1YWxpemF0aW9uClJlc2lkdWFscyA8LSAoaGl2X2Rpc3QgLSBwb3B1bGF0aW9uX2Rpc3QpIC8gc3FydChwb3B1bGF0aW9uX2Rpc3QpCnBsb3QoUmVzaWR1YWxzLCB0eXBlPSdoJywgeWxhYj0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHhsYWI9J1Byb3BvcnRpb24gb2YgUG9zaXRpdmUgSElWJywgbWFpbj0nUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWwgZm9yIEFnZSBhbmQgSElWIFBvc2l0aXZlJykKYGBgCk51bGwgSHlwb3RoZXNpczogVGhlIHByb3BvcnRpb24gb2YgYWdlIGluIHRoZSBwb3B1bGF0aW9uIGlzIHVucmVsYXRlZCB3aXRoIHRoZSBwcm9wb3J0aW9uIG9mIHBlb3BsZSBoYXZpbmcgaGl2LihBZ2UgaXMgbm90IGFuIGluZmx1ZW5jaW5nIGZhY3RvciBmb3IgSElWIHRlc3RpbmcgcG9zaXRpdmUpClNpbmNlIHAtdmFsdWUgb2YgdGhpcyBjaGktc3F1YXJlIGdvb2RuZXNzIG9mIGZpdCB0ZXN0IGlzIGNsb3NlIHRvIDEsIHdlIHNlZSB0aGF0IGRldmlhdGlvbnMgYXMgbGFyZ2UgYXMgb3VycyAob3IgbGFyZ2VyKSBhcmUgdmVyeSBsaWtlbHkuIEluIGFkZGl0aW9uLCBoYXZpbmcgdmFsdWVzIG9mIHRoZSBzdGFuZGFyZGl6ZWQgcmVzaWR1YWwgbGVzcyB0aGFuIDMgc3VnZ2VzdHMgdGhhdCBpdCBpcyBhIGdvb2QgZml0IG9mIHRoZSBhZ2UgZGlzdHJpYnV0aW9uIHRvIGVzdGltYXRlIHRoZSBwZW9wbGUgdGVzdGluZyBwb3NpdGl2ZSBvbiBoaXYuIEhlbmNlLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBhbmQgY29uY2x1ZGUgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHByb3BvcnRpb24gb2YgYWdlIG1hdGNoZXMgd2l0aCB0aGUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwZW9wbGUgdGVzdGluZyBwb3NpdGl2ZSBvbiBISVYu